In a class template Foo
I want to check if the template parameter provides a type named Bar
.
struct TypeA {using Bar = int;};
struct TypeB {};
template<class T>Foo{};
void main(){
Foo<TypeA> a; // I want this to compile
Foo<TypeB> b; // I want this to not compile, but print a nice message.
}
Since I want to combine this with other properties I want a hasBar
metafunction. So I can combine the boolean values and then use std::enable_if
.
I tried to understand and use SFINAE but failed:
template<class T, class Enable = void>struct hasBar : std::false_type {};
template<class T>
struct hasBar<T,decltype(std::declval<T::Bar>(),void())> : std::true_type {};
hasBar<TypeA>::value
is always false.
What is the right way to define hasBar
?
Or is there some better approach then using
to have a Bar?
The simplest way would be to use the dependent type as the default value for an unnamed template parameter. Something like this:
struct with_bar { using Bar = int; };
struct without_bar { };
template <typename T, typename = typename T::Bar>
struct bar_detector { };
int main() {
bar_detector<with_bar>();
bar_detector<without_bar>(); // won' compile
}
This yields a pretty usable error message ( g++ 7.3.0
): error: no type named 'Bar' in 'struct without_bar'
.
You should add typename
before T::Bar
to specify that it's a nested type name, ie
template<class T>
struct hasBar<T,decltype(std::declval<typename T::Bar>(),void())> : std::true_type {};
BTW: You can use std::void_t
to make it simpler. eg
template< class, class = std::void_t<> >
struct hasBar : std::false_type { };
template< class T >
struct hasBar<T, std::void_t<typename T::Bar>> : std::true_type { };
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.