在 C++11 中使用 SFINAE 在具有相同签名的两个函数之间进行选择
Using SFINAE in C++11 to choose between two functions with same signature
我正在尝试在 c++11 中使用 SFINAE 在两个具有相同签名但不同主体的函数之间进行选择,具体取决于给定T
类型中应该有或没有typedef
的事实。例如,我有两个结构,一个定义了 MyTypedef,另一个什么都没有:
struct MyStruct1
{
typedef std::false_type MyTypedef;
...
}
struct MyStruct3
{
...
}
然后我有两个模板函数,它们应该将结构的类型作为 T 并根据MyTypedef
的存在做不同的事情。特别是,如果定义了T::MyTypedef
,我应该调用第一个函数,在所有其他情况下,我应该调用第二个函数。我尝试了这样的事情:
template<typename T>
void myFunction()
{
...
}
template<typename T, typename std::enable_if<T::MyTypedef>::type* = nullptr>
typename myFunction()
{
...
}
但它不编译,错误是 C2668 (MSVC( - '函数' :对重载函数的不明确调用
您可以编写一个特征来检测 typedef 是否存在,例如,使用 void_t
和基于此的 SFINAE
template<class...> struct voider { using type = void; };
template<class... Ts> using void_t = typename voider<Ts...>::type;
template<class T, class = void>
struct has_MyTypedef : std::false_type {};
template<class T>
struct has_MyTypedef<T, void_t<typename T::MyTypedef>> : std::true_type {};
template<typename T, std::enable_if_t<has_MyTypedef<T>{}, int> = 0>
void myFunction()
{
...
}
template<typename T, std::enable_if_t<!has_MyTypedef<T>{}, int> = 0>
void myFunction()
{
...
}
或者编写内部帮助程序,以便在两个可行的情况下使用虚拟参数消除它们之间的歧义:
template<class T, class = typename T::MyTypedef>
void myFunctionImpl(int) {
// ...
}
template<class T>
void myFunctionImpl(...) {
// ...
}
template<class T>
void myFunction(){
return myFunctionImpl<T>(0);
}
您的代码无法编译,因为在"has typedef"情况下,两个重载都存在并且有效。 编译器无法在它们之间进行选择。 有 3 种基本方法。
首先,简单地反转条件。 你以 sfinae 友好的方式编写"有 typedef"和"没有 typedef",如果有,则启用一个函数,如果没有,则启用另一个函数。
我发现这通常是丑陋的,而且缩放很差。
第二种方法是,当两者都有效时,通过使用重载解析顺序技巧(继承、varargs、转换等(,首选您想要的那个。 这个缩放稍微好一点,但我发现它有点笨拙,有点脆。
第三种方法是标记调度。 这不能很好地支持"没有有效的重载",但在其他方面是干净的。
你写一个基函数。 此函数执行一些类型计算,并使用结果构建一些标记类型。 然后,使用标记调用实现函数,并使用它来调度。
想象一下,你有特质has_foo<T>
. 如果类型T
具有属性 foo
,则它是从 std::true_type
继承的类型,否则false_type
。
然后我们可以:
void bar_impl(std::true_type);
void bar_impl(std::false_type);
template<class T>
void bar(T const&){
bar_impl( has_foo<T>{} );
}
并调用对应于 T
是否具有属性foo
的bar_impl
。
编写这样的测试很容易。 这里有一个小库:
namespace details{
template<template<class...>class Z, class, class...>
struct can_apply:std::false_type{};
template<template<class...>class Z, class...Ts>
struct can_apply<Z, decltype(void(std::declval<Z<Ts...>>())), Ts...>:
std::true_type
{};
}
template<template<class...>class Z,class...Ts>
using can_apply=typename details::can_apply<Z,void,Ts...>::type;
然后我们只写我们的测试:
template<class T>
using bob_subtype = typename T::bob;
是类型 T::bob
. 我们可以测试某物是否有鲍勃:
template<class T>
using has_bob=can_apply<bob_subtype,T>;
并完成了。
- 如何巧妙地编写两个函数——一个用于检查是否存在解决方案,另一个用于获取所有解决方案
- 两个函数模板候选项.将一个参数作为引用后,选择不太专业的模板
- 如何比较两个函数的速度和性能
- 如何在构造器的成员初始值设定项列表中调用两个函数?
- 如何将这两个函数组合成一个实现?
- 将具有相反操作数的两个函数重构为一个
- 创建整数的 2D 数组,该数组将使用两个函数用随机数填充矩阵.我做错了什么?
- 具有相同主体的两个函数具有不同的名称
- 通过作为类的公共成员的两个函数将函数作为参数传递
- 如何使用排序和比较这两个函数在 c++ 中对字符数组进行排序?
- 是否可以在C++中将两个函数一起添加
- C++ 两个函数除了一行之外执行相同的操作
- 如何编写连接两个函数的函数
- 如何执行两个函数参数具有相同的模板类型
- 当两个函数位于一行中时,堆栈框架的样子
- 为什么这两个函数的行为不同
- 为什么当我有两个函数时编译器没有显示错误,一个将采用基类,一个将派生类作为参数
- 系统堆栈中的两个函数的递归调用(将不同数量的数组作为参数传递)有什么区别
- 如何在一个构造函数中使用两个可变参数模板参数来绑定两个函数
- 如何在c++中的两个函数中传递对象的同一实例