Проверка концепции не компилируется в 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);
}