I am trying to use some SFINAE inside a templated struct. I reduced my problem to the following and could make this work:
template<bool mybool>
struct test {
void myfunc();
};
template<bool mybool>
void test<mybool>::myfunc() {
std::cout << "test true" << std::endl;
}
template<>
void test<false>::myfunc() {
std::cout << "test false" << std::endl;
}
int main(int argc, char ** argv) {
test<true> foo;
test<false> bar;
foo.myfunc();
bar.myfunc();
}
With this code, I get the result:
test true
test false
However, if I want to consider that my struct test
with more than one template parameter, I tried adapting the above like this:
template<int myint, bool mybool>
struct test {
void myfunc();
};
template<int myint, bool mybool>
void test<myint,mybool>::myfunc() {
std::cout << "test true" << std::endl;
}
template<int myint>
void test<myint,false>::myfunc() {
//error: invalid use of incomplete type 'struct test<myint, false>'
std::cout << "test false" << std::endl;
}
int main(int argc, char ** argv) {
test<1,true> foo;
test<1,false> bar;
foo.myfunc();
bar.myfunc();
}
I am getting an invalid use of incomplete type 'struct test'.
Am I going in the wrong direction? Is there a way to do what I want to do? Thanks for your help!
You cannot partially specialize member function, you should partially specialize
full struct. Following example will work correctly
template<int myint, bool mybool>
struct test {
void my_func();
};
template<int myint, bool mybool>
void test<myint,mybool>::my_func() {
std::cout << "test true" << std::endl;
}
template<int myint>
struct test<myint, false> {
void my_func();
};
template<int myint>
void test<myint,false>::my_func() {
//error: invalid use of incomplete type 'struct test<myint, false>'
std::cout << "test false" << std::endl;
}
int main(int argc, char ** argv) {
test<1,true> foo;
test<1,false> bar;
foo.my_func();
bar.my_func();
}
If you want to avoid redefining your class, which you would have to do since partial specialisation of (member) functions is not allowed, you could decompose your type. This will minimise the repetition of code:
template<int myint, bool mybool>
struct test {
char some_var;
std::vector<int> more_var;
void my_func();
};
Change to:
template<int myint>
struct test_static {
protected:
char some_var;
std::vector<int> more_var;
};
template <int myint, bool mybool>
struct test : private test_static<myint> {
void my_func() {
// default case
}
};
template <int myint>
struct test<myint,false> : private test_static<myint> {
void my_func() {
// special case
}
};
Of course, if you want full visibility of all members to the outside, don't make them protected
in the first place and use public
instead of private
inheritance.
Looking first at this question on the SFINAE principle to refresh my memory, I tried to get the result you are looking for with minimal redundancy in the code.
I also checked the wikipedia article on the subject, which indicated me that you need a functionality similar too boost::enable_if
to conditionally choose your function inmplementation:
// simplified version of boost::enable_if_c and disable_if_c to match your exact need
template <bool B>
struct enable_if_c {
typedef void type;
};
struct enable_if_c<false>{};
template <bool B>
struct disable_if_c {
typename void type;
};
struct disable_if_c<true> {};
template<bool mybool, typename T>
struct test {
template <bool d>
typename enable_if_c<d>::type my_func_impl(){
cout << "true" << endl;
}
template <bool d>
typename disable_if_c<d>::type my_func_impl(){
cout << "false" << endl;
}
void my_func(){ my_func_impl<mybool>(); }
};
You can define the my_func_impl
bodies outside the struct with the following syntax:
template <bool mybool, typename T>
template <bool d>
typename enable_if_c<d>::type test<mybool,T>::my_func_impl(){
cout << "true" << endl;
}
The tricky point of the problem is that you cannot rely on a simple overloading, since you want the same function prototype, hence the need to exclusively define one or the other implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With