C++11 与bind一起使用时,is_base_的错误行为
使用可变模板参数和一个简单的模板参数,当它从绑定的函子实例化时,我经历了一些奇怪的行为,is_base_of 代码如下:C++11 与bind一起使用时,is_base_的错误行为,c++11,bind,variadic-templates,typetraits,C++11,Bind,Variadic Templates,Typetraits,使用可变模板参数和一个简单的模板参数,当它从绑定的函子实例化时,我经历了一些奇怪的行为,is_base_of 代码如下: 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,
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;
}
但我希望:
0
1
1
我是否以错误的方式使用可变模板?有没有其他(正确的)方法来获取变量类型列表的第一种类型,比如Args?为什么只有当它与bind表达式一起使用时才会出现问题
请注意,如果我将基本模板修改为只有一个模板参数,则绑定表达式可以工作:
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;
}
模板
类基{};
模板
结构检查器{
typedef int result_type;
//如果给定的T类型是Base的后代,则返回1
模板
结果类型运算符()(参数和参数)
{
返回检查(std::is_base_of(),
标准:正向(参数);
}
模板
结果类型检查(const std::true\u type&,Args&…params)
{
返回1;
}
模板
结果类型检查(常量std::false类型&,参数&…参数)
{
返回0;
}
};
结构A{};
结构B:Base{};
int main()
{
检查器ch1;
std::cout由于在std::bind()
之后调用Checker
函数对象时,First
的数据类型为int&
,而不是int
,因此无法获得预期的输出
因此,std::is_base_of
不会为调用Checker::check
实例化为std::true_类型
问题是,std::bind
正在创建一个对象,该对象在内部存储要传递给它的函数的参数。因此,std::bind
返回的对象的非静态数据成员中有一个命名的l值,该值保存了作为要绑定到函数的参数传递的值。当非静态数据成员在调用函子的操作符()
时被传递到r值引用,它作为l值引用传递,因为它不再是临时对象。如果执行以下操作,则会出现类似问题:
int x = 1;
Checker<B> ch2;
std::cout<<ch2(x, 3.14)<<std::endl;
template<typename First, typename ...Args>
result_type operator()(First&& first, Args&&... params)
{
if (std::is_reference<First>::value)
{
return check(std::is_base_of<Base<T, typename std::remove_reference<First>::type>, T>(),
std::forward<First>(first),
std::forward<Args>(params)...);
}
else
{
return check(std::is_base_of<Base<T,First>, T>(),
std::forward<First>(first),
std::forward<Args>(params)...);
}
}
这将删除对象的引用类型,并提供所需的结果。不幸的是,std::is_reference没有在更复杂的问题上提供预期的结果。
因此,最后我选择提供引用和常量引用重载:
template<typename First, typename ...Args>
result_type operator()(First& first, Args&&... params)
{
return check(std::is_base_of<Base<T,First>, T>(),
first,
std::forward<Args>(params)...);
}
template<typename First, typename ...Args>
result_type operator()(const First& first, Args&&... params)
{
return check(std::is_base_of<Base<T,First>, T>(),
first,
std::forward<Args>(params)...);
}
模板
结果类型运算符()(第一个和第一个参数和…参数)
{
返回检查(std::is_base_of(),
第一,
标准:正向(参数);
}
模板
结果类型运算符()(常量First和First,参数&&…params)
{
返回检查(std::is_base_of(),
第一,
标准:正向(参数);
}
是的,确实如此。但是有没有办法以某种方式将其作为int传递,而不是int&?为什么以及如何将其变成int&而不是int?谢谢你,Jason,这帮了大忙。我想问一下,为什么要将其实现为函数而不是元函数?当所有检查都可以在编译时完成时,涉及一个值似乎完全没有必要。我很想知道,意外的结果是什么?顺便说一句,请记住常量左值引用不会绑定到非常量右值引用,因此如果没有该类型的特定重载,您将无法传递常量左值参数而不会导致编译器错误。只有常量右值引用才能绑定任何对象他们。
template<typename First, typename ...Args>
result_type operator()(First& first, Args&&... params)
{
return check(std::is_base_of<Base<T,First>, T>(),
first,
std::forward<Args>(params)...);
}
template<typename First, typename ...Args>
result_type operator()(const First& first, Args&&... params)
{
return check(std::is_base_of<Base<T,First>, T>(),
first,
std::forward<Args>(params)...);
}