概念检查器不会在 GCC 上编译,因为它'has no linkage'

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

本文关键字:因为 linkage no has 编译 检查 GCC      更新时间:2023-10-16

我基于这个问题创建了一个概念检查类,其目的是确保给定的类具有一个名为baseUnitConversionFactor的静态成员函数。该类在msvc2013上编译并运行良好,但它不会在gcc 4.9.2上编译(使用-std=c++14),错误为:

错误:"{匿名}::UnitsTest_conceptChecker_Test::TestBody()::validUnit::baseUnitConversionFactor"不是类型"double(*)()"的有效模板参数,因为"static double{匿名}::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);
}

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

这一限制在C++17中被N4268删除,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。

要进行更全面的检查,您可能需要查看std::experimental::is_detected_convertible。该cppreference页面有一个引用实现。

令人烦恼的是,这个问题似乎是由gtest使用匿名名称空间的方式引起的。将validUnit声明移动到测试fixture(称为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);
}
相关文章: