让我们说,我有六种类型,它们各自都属于一个概念类别 这是一个显示这一点的图表:
或许也许是一个更具体的例子:
我想写两个能处理所有6种类型的函数 “类别1”中的类型以某种方式处理,“类别2”中的类型以不同的方式处理。
让我们进入代码。 首先,我将创建六种类型。
//Category 1 Types
class Type_A{};
class Type_B{};
class Type_C{};
//Category 2 Types
class Type_D{};
class Type_E{};
class Type_F{};
接下来,我将创建两个类型特征,以便在编译时可以发现类型的类别。
/* Build The Category 1 Type Trait */
//Type_A Type Trait
template <typename T>
struct Is_Type_A {
static const bool value = false;
};
template <>
struct Is_Type_A<Type_A> {
static const bool value = true;
};
//Type_B Type Trait
template <typename T>
struct Is_Type_B {
static const bool value = false;
};
template <>
struct Is_Type_B<Type_B> {
static const bool value = true;
};
//Type_C Type Trait
template <typename T>
struct Is_Type_C {
static const bool value = false;
};
template <>
struct Is_Type_C<Type_C> {
static const bool value = true;
};
//Category 1 Type Trait
template <typename T>
struct Is_Type_From_Category_1 {
static const bool value = Is_Type_A<T>::value || Is_Type_B<T>::value || Is_Type_C<T>::value;
};
/* Build The Category 2 Type Trait */
//Type_D Type Trait
template <typename T>
struct Is_Type_D {
static const bool value = false;
};
template <>
struct Is_Type_D<Type_D> {
static const bool value = true;
};
//Type_E Type Trait
template <typename T>
struct Is_Type_E {
static const bool value = false;
};
template <>
struct Is_Type_E<Type_E> {
static const bool value = true;
};
//Type_F Type Trait
template <typename T>
struct Is_Type_F {
static const bool value = false;
};
template <>
struct Is_Type_F<Type_F> {
static const bool value = true;
};
//Category 1 Type Trait
template <typename T>
struct Is_Type_From_Category_2 {
static const bool value = Is_Type_D<T>::value || Is_Type_E<T>::value || Is_Type_F<T>::value;
};
现在我有两种类型特征来区分六种类型中的每一种类型,我想写两个函数。一个函数将接受来自类别1的所有内容,而另一个函数将接受来自类别2的所有内容。有没有办法在不创建某种调度功能的情况下执行此操作?我能找到一种只有两种功能的方法;每个类别一个?
编辑:我曾试图像这样使用enable_if,但这样的尝试会导致编译错误。
//Handle all types from Category 1
template<class T ,class = typename std::enable_if<Is_Type_From_Category_1<T>::value>::type >
void function(T t){
//do category 1 stuff to the type
return;
}
//Handle all types from Category 2
template<class T ,class = typename std::enable_if<Is_Type_From_Category_2<T>::value>::type >
void function(T t){
//do category 2 stuff to the type
return;
}
编辑2:我已经尝试过链接中提供的代码,但这不是关于是否调用该函数的是或否决定。给定两种类型特征,我可以调用哪个函数。这将是重新定义错误。
//Handle all types from Category 2
template<class T, class dummy = typename std::enable_if< Is_Type_From_Category_1<T>::value, void>::type>
void function(T t){
//do category 1 stuff to the type
return;
}
//Handle all types from Category 2
template<class T, class dummy = typename std::enable_if< Is_Type_From_Category_2<T>::value, void>::type>
void function(T t){
//do category 2 stuff to the type
return;
}
答案 0 :(得分:11)
不允许两个函数签名仅因模板参数的默认值而不同。如果您明确调用function< int, void >
?
enable_if
的常用用法是函数返回类型。
//Handle all types from Category 1
template<class T >
typename std::enable_if<Is_Type_From_Category_1<T>::value>::type
function(T t){
//do category 1 stuff to the type
return;
}
//Handle all types from Category 2
template<class T >
typename std::enable_if<Is_Type_From_Category_2<T>::value>::type
function(T t){
//do category 2 stuff to the type
return;
}
答案 1 :(得分:10)
我认为使用标签发送会比SFINAE更容易。
template<class T>
struct Category;
template<>
struct Category<Type_A> : std::integral_constant<int, 1> {};
template<>
struct Category<Type_B> : std::integral_constant<int, 1> {};
template<>
struct Category<Type_C> : std::integral_constant<int, 1> {};
template<>
struct Category<Type_D> : std::integral_constant<int, 2> {};
template<>
struct Category<Type_E> : std::integral_constant<int, 2> {};
template<>
struct Category<Type_F> : std::integral_constant<int, 2> {};
template<class T>
void foo(std::integral_constant<int, 1>, T x)
{
// Category 1 types.
}
template<class T>
void foo(std::integral_constant<int, 2>, T x)
{
// Category 2 types.
}
template<class T>
void foo(T x)
{
foo(Category<T>(), x);
}
答案 2 :(得分:3)
作为通过“traits”选择类别的替代方法,您还可以考虑CRTP(类型以类别为基础):
template<class Derived> class category1 {};
template<class Derived> class category2 {};
class A1: public category1<A1> { ..... };
class A2: public category2<A2> { ..... };
class B1: public category1<B1> { ..... };
class B2: public category2<B2> { ..... };
template<class T>void funcion_on1(category1<T>& st)
{
T& t = static_cast<T&>(st);
.....
}
template<class T>void funcion_on1(category2<T>& st)
{
T& t = static_cast<T&>(st);
.....
}
优点是具有污染较少的命名空间。
答案 3 :(得分:3)
我从R. Martinho Fernandes学到了以下技巧。下面显示的代码是为了说明问题的基础,但你应该参考这个blog post来获得完整的技巧来使它漂亮。
您已经提到过,由于签名相同,您遇到了问题。诀窍是使类型不同。
您的第二种方法已接近,但我们无法使用void
作为std::enable_if<>
的结果类型。
请注意,以下代码无法编译,并且为void
指定std::enable_if<>
不会更改任何内容,因为默认情况下为void
。
#include <iostream>
class A {};
class B {};
template <
typename T,
typename = typename std::enable_if<std::is_same<T, A>::value>::type>
void F(T) {
std::cout << "A" << std::endl;
}
template <
typename T,
typename = typename std::enable_if<std::is_same<T, B>::value>::type>
void F(T) {
std::cout << "B" << std::endl;
}
int main() {
F(A{});
F(B{});
}
正如您所描述的那样,原因是签名是相同的。让我们区分它们。
#include <iostream>
class A {};
class B {};
template <
typename T,
typename std::enable_if<std::is_same<T, A>::value, int>::type = 0>
void F(T) {
std::cout << "A" << std::endl;
}
template <
typename T,
typename std::enable_if<std::is_same<T, B>::value, int>::type = 0>
void F(T) {
std::cout << "B" << std::endl;
}
int main() {
F(A{});
F(B{});
}
打印:
A
B
我们现在区分了两个函数之间的类型,因为它不是第二个模板参数,而是一个类型,它现在是int
。
这种方法比在返回类型中使用std::enable_if<>
更可取,例如,因为构造函数没有返回类型,所以模式不适用于那些。
注意:std::is_same<>
与单个类一起使用以简化条件。