概念检查器不会在gcc上编译,因为它没有链接'

时间:2015-12-28 21:45:23

标签: c++ c++11 gcc c++-concepts

我已经基于this question创建了一个概念检查类,其目的是确保给定的类具有名为baseUnitConversionFactor的静态成员函数。该类使用msvc2013编译并正常工作,但它不能在gcc 4.9.2(使用-std = c ++ 14)上编译并出现错误:

  

错误:'{anonymous} :: UnitsTest_conceptChecker_Test :: TestBody():: validUnit :: baseUnitConversionFactor'   不是类型'double(*)()'的有效模板参数,因为   'static double {anonymous} :: UnitsTest_conceptChecker_Test :: TestBody():: validUnit :: baseUnitConversionFactor()'   没有联系

     

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

我真的不知道这意味着什么,而且更熟悉在视觉工作室中编写模板(显然)更为谨慎的环境。任何人都可以帮助弄清楚我需要做些什么来解决这个问题?

概念检查器类

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_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);
}

2 个答案:

答案 0 :(得分:2)

在C ++ 11和C ++ 14中,指针/引用模板参数必须引用具有链接的实体(在C ++ 03中,它们仅限于具有外部链接的实体)。本地类没有链接,它的成员函数也没有。

此限制已在{+ 3}}中在C ++ 17中删除,而GCC主干声称已实施该论文,但显然不是链接部分。

避免此问题的步骤不需要使用&U::baseUnitConversionFactor作为模板非类型参数。令人高兴的是,测试表达式T::baseUnitConversionFactor()有效且准确返回double的更简单方法是:

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

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

这取决于表达式SFINAE(但原来也是如此),所以我不确定它是否适用于MSVC 2013.

要进行更一般的检查,您可能需要查看N4268。该cppreference页面有一个参考实现。

答案 1 :(得分:0)

令人讨厌的是,这个问题似乎是由gtest使用匿名命名空间的方式引起的。将validUnit声明移动到测试夹具(称为UnitsTest)并更改EXPECT语句以使用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;
    };
};

更新测试

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