Using variadic template arguments together with a simple template argument I have experienced some strange behaviour of is_base_of when it was instantiated from a binded functor.
Here is the code:
template <class T, class Index>
class Base{};
template<typename T>
struct Checker {
typedef int result_type;
// Returns 1 if a given T type is descendant of Base<T,First>
template<typename First, typename ...Args>
result_type operator()(First&& first, Args&&... params)
{
return check(std::is_base_of<Base<T,First>, T>(),
std::forward<First>(first),
std::forward<Args>(params)...);
}
template<typename ...Args>
result_type check(const std::true_type&, Args&&... params)
{
return 1;
}
template<typename ...Args>
result_type check(const std::false_type&, Args&&... params)
{
return 0;
}
};
struct A {};
struct B : Base<B,int> {};
int main()
{
Checker<A> ch1;
std::cout<<ch1(3.14)<<std::endl;
Checker<B> ch2;
std::cout<<ch2(1 ,3.14)<<std::endl; // output is 1
std::cout<<std::bind(ch2, 1, 3.14)()<<std::endl; // output is 0 but it should be 1 !
return 0;
}
The program output is:
0
1
0
But I would expect:
0
1
1
Am I using the variadic templates in a wrong way? Is there any other (correct) way to get the first type of a variadic type list like Args? Why this is a problem only when it is used with the bind expression?
Note, if I am modifing the Base template to have only one template parameter, then the bind expression works:
template <class T>
class Base{};
template<typename T>
struct Checker {
typedef int result_type;
// Returns 1 if a given T type is descendant of Base<T>
template<typename ...Args>
result_type operator()(Args&&... params)
{
return check(std::is_base_of<Base<T>, T>(),
std::forward<Args>(params)...);
}
template<typename ...Args>
result_type check(const std::true_type&, Args&&... params)
{
return 1;
}
template<typename ...Args>
result_type check(const std::false_type&, Args&&... params)
{
return 0;
}
};
struct A {};
struct B : Base<B> {};
int main()
{
Checker<A> ch1;
std::cout<<ch1(3.14)<<std::endl;
Checker<B> ch2;
std::cout<<ch2(3.14)<<std::endl; // output is 1
std::cout<<std::bind(ch2, 3.14)()<<std::endl; // output is 1 this time!
return 0;
}
Unfortunately std::is_reference did not give me the expected result on a more complicated issue.
So finally I choosed providing the reference and const-reference overloads: