I have a simple SFINAE check for the existence of a static member function using C++17's std::void_t
:
template <class T, class X = void>
struct has_bar {
static const bool value = false;
};
template <class T>
struct has_bar<T, std::void_t<decltype(T::bar(std::declval<int&>()))>> {
static const bool value = true;
};
The class Foo
obviously has a bar
member function taking an int&
as its only argument, the class NoBar
has no such member function:
struct Foo
{
static void bar(int& value)
{
value = 42;
}
};
struct NoBar{};
Using has_bar
in a static_assert
works as expected, but using it in an ASSERT_TRUE
statement yields a compiler error:
TEST(SFINAE, has_bar)
{
static_assert(!has_bar<NoBar>::value);
static_assert(has_bar<Foo>::value);
ASSERT_FALSE(has_bar<NoBar>::value);
//why does this not work??
ASSERT_TRUE(has_bar<Foo>::value);
}
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
ASM generation compiler returned: 0
/opt/compiler-explorer/gcc-10.2.0/bin/../lib/gcc/x86_64-linux-gnu/10.2.0/../../../../x86_64-linux-gnu/bin/ld: /tmp/ccfSP5vL.o: in function `SFINAE_has_bar_Test::TestBody()':
/home/ce/<source>:42: undefined reference to `has_bar<Foo, void>::value'
collect2: error: ld returned 1 exit status
Execution build compiler returned: 1
Is this a google test bug or am I missing something here?
This error occurs because has_bar::value
has been declared but not defined. Somehow, the ASSERT_TRUE
macro has odr-used this object. It's not necessary to understand exactly what ASSERT_TRUE
is doing; you should always define your static class members.
The easiest way to do this is to inherit from std::false_type
and std::true_type
instead of declaring a static member named value
. The standard library already contains a definition for the inherited value
member, so you don't have to provide your own.
In C++17, note that static constexpr bool value = false;
is a definition by itself (and is implicitly inline
). But this isn't the case if the member is merely const
and not constexpr
, so you see the issue in both C++14 and C++17 mode.