Проверка концепции не компилируется в gcc, потому что она "не имеет связи"

Я создал класс проверки концепции, основанный на этом вопросе, цель которого - убедиться, что у данного класса есть статическая функция-член, называемая 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() ' не имеет связи

статический тест std::true_type (tester<& U:: baseUnitConversionFactor>*);

Я на самом деле не знаю, что это значит, и я гораздо лучше знаком с написанием шаблонов в визуальных студиях (очевидно), гораздо более всепоглощающей средой. Может кто-нибудь помочь выяснить, что мне нужно сделать, чтобы это исправить?

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_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 ответа

Решение

В 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 объявление в тестовом приборе (называемое UnitsTest) и изменение оператора EXPECT для использования пространства имен фикстера решило проблему.

Обновленный светильник

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);
}
Другие вопросы по тегам