concept checker doesn't compile on gcc because it 'has no linkage'

冷暖自知 提交于 2019-12-12 03:28:50

问题


I've created a concept checking class based on this question whose purpose is to make sure a given class has a static member function called baseUnitConversionFactor. The class compiles and works fine with msvc2013, but it wont compile on gcc 4.9.2 (using -std=c++14) with the error:

error: ‘{anonymous}::UnitsTest_conceptChecker_Test::TestBody()::validUnit::baseUnitConversionFactor’ is not a valid template argument for type ‘double (*)()’ because ‘static double {anonymous}::UnitsTest_conceptChecker_Test::TestBody()::validUnit::baseUnitConversionFactor()’ has no linkage

static std::true_type test(tester<&U::baseUnitConversionFactor>*);

I don't really know what that means, and am much more familiar with writing templates in visual studios (obviously) much more permisive enviornment. Can anyone help figure out what I need to do to fix this?

Concept Checker Class

template <typename T>
struct has_baseUnitConversionFactor
{
    template<double(*)()> struct tester;

    template<typename U>
    static std::true_type test(tester<&U::baseUnitConversionFactor>*);
    template<typename U>
    static std::false_type test(...);

    static const bool value = decltype(test<T>(0))::value;
};

Test which I think causes the error

TEST_F(UnitsTest, conceptChecker)
{
    struct validUnit
    {
        static inline double baseUnitConversionFactor() { return 0.0; }
        typedef void unit_category;
        typedef void base_unit_type;
    };

    EXPECT_TRUE(has_baseUnitConversionFactor<validUnit>::value);
}

回答1:


In C++11 and C++14, pointer/reference template arguments must refer to entities with linkage (in C++03, they were limited to entities with external linkage). A local class has no linkage, and neither do its member functions.

This restriction has been removed in C++17 by N4268, and GCC trunk claims to have implemented that paper, but apparently not the linkage part.

Sidestepping this issue requires not using &U::baseUnitConversionFactor as a template non-type argument. Happily, a much simpler way to test that the expression T::baseUnitConversionFactor() is valid and returns exactly double is:

template <typename T, class=double>
struct has_baseUnitConversionFactor : std::false_type { };

template <typename T>
struct has_baseUnitConversionFactor<T, decltype(T::baseUnitConversionFactor())>
         : std::true_type { };

This does depend on expression SFINAE (but then, so does the original), so I'm not sure if it will work on MSVC 2013.

For a more general check, you may want to look at std::experimental::is_detected_convertible. That cppreference page has a reference implementation.




回答2:


Annoyingly, the problem seems to be caused by the way gtest uses anonymous namespaces. Moving the validUnit declaration into the test fixture (called UnitsTest) and changing the EXPECT statement to use the fixture namespace solved the issue.

Updated Fixture

class UnitsTest : public ::testing::Test {
protected:

    UnitsTest()
    {

    }

    virtual ~UnitsTest()
    {

    }

    virtual void SetUp()
    {

    }

    virtual void TearDown()
    {

    }

    struct validUnit
    {
        static inline double baseUnitConversionFactor() { return 0.0; }
        typedef void unit_category;
        typedef void base_unit_type;
    };
};

Updated Test

TEST_F(UnitsTest, conceptChecker)
{
    EXPECT_TRUE(has_baseUnitConversionFactor<UnitsTest::validUnit>::value);
}


来源:https://stackoverflow.com/questions/34501232/concept-checker-doesnt-compile-on-gcc-because-it-has-no-linkage

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!