I want to pick a specialization of a template when a certain type is defined.
I still cannot wrap my head around SFINAE :(. I might be close or I might be completely off. I tried different things and this is something, I at least hope to understand why it does not work (is_complete
basically stolen from here):
#include <iostream>
#include <type_traits>
template <typename T, class = void>
struct is_complete : std::false_type {};
template <typename T>
struct is_complete<T,decltype(void(sizeof(T)))> : std::true_type {};
// this should be called if foo is not defined
void test() { std::cout << "test base\n"; }
// forward declare foo
struct foo;
// this should be called if foo is defined
template <typename T>
std::enable_if<is_complete<foo>::value,void> test() {
foo::bar();
}
// this is either defined or not
struct foo{
static void bar() { std::cout << "foo bar\n"; }
};
int main(){
test();
}
With gcc 4.8 (-std=c++11
) i get :
if_type_defined.cpp: In instantiation of ‘struct is_complete<foo>’:
if_type_defined.cpp:16:32: required from here
if_type_defined.cpp:8:42: error: invalid application of ‘sizeof’ to incomplete type ‘foo’
struct is_complete<T,decltype(void(sizeof(T)))> : std::true_type {};
^
if_type_defined.cpp:8:42: error: invalid application of ‘sizeof’ to incomplete type ‘foo’
if_type_defined.cpp: In function ‘std::enable_if<true, void> test()’:
if_type_defined.cpp:17:3: error: incomplete type ‘foo’ used in nested name specifier
foo::bar();
^
I think I know more or less what is wrong: foo
does not depend on T
, hence no substitution needed to get foo
and I get a hard error instead of Not An Error. Next I tried to use a helper along the line of
template <typename T>
struct make_foo_dependent {
using type = foo;
};
and tried to use that inside the enable_if
instead of foo
directly. However, this just added more errors and I didnt include it here, because I am afraid this is also going in the wrong direction.
How can I choose what function to call depending on whether foo
is defined? If foo
is not defined, the code using foo
should not issue a hard error, but simply be ignored by the compiler.
PS: Lots has changed with respect to SFINAE, and I find it hard to find ressources that restrict themself to C++11, where things seem to be a bit more hairy than in newer standards.
test();
will never invoke that function because it is a template that requires at least one argument. – Nevemake_foo_dependent
should've worked. It is actually a right direction. – Nevefoo
, I guess it can only work when also the base case is a template. Dont remember where i got the idea that it can be non-template – Susiestruct is_complete
and code (SFINAE) based on it. You quickly can have ODR violations NDR. – Harquebus