为白名单类型约束模板函数的更好方法,SFINAE

Better way for constrain template function for white listed types, SFINAE?

本文关键字:函数 更好 方法 SFINAE 约束 白名单 名单 类型      更新时间:2023-10-16

我想创建一个特性/接口,例如is_good,并针对其规范实现我的通用函数。

在一些关于SFINAE的在线资源的帮助下,我想出了以下代码。

template<class C>
struct is_good: std::false_type
{
};
template<>
struct is_good<A<double, 2>>: std::true_type
{
};
template<>
struct is_good<B<double, 2, 3>>: std::true_type
{
};
template<template<class> class C, class T>
using check_constraints = std::enable_if_t<C<T>::value, bool>;
}

我的通用函数定义如下:

template<class T, template<class> class C = is_good,
typename = check_constraints<C, T>>
void compute(const T& t) {}

使用

// works
compute(A<double,2>());
compute(B<double,2, 3>());
// should not compile.
compute(B<double,5, 6>());

然而,这似乎有点麻烦。我必须准备

template<class T, template<class> class C = is_good,
typename = check_constraints<C, T>>

到我计划通用化的所有函数。

有更好的方法吗?

更新

这个问题的基础是,假设我知道我的函数体与类型A&B&C,我如何定义我的函数?

例如,在其他语言中,也许你可以做

using T = Union{A, B, C};
void compute(T t){...}
# works with A
compute(A());
# works with B
compute(B());

无论CCD_ 5看起来如何。

您的问题不清楚。但是,如果is_2d必须在所有函数中,为什么不将其移动到check_constraints呢?参考编号:https://gcc.godbolt.org/z/s9Jql-

template<class T>
using check_constraints = std::enable_if_t<is_2d<T>::value, bool>;
template<class T, typename = check_constraints<T>>
void compute(const T& t){
works(t);
}

更新

如果你只想要一个允许的类型列表,下面的更好,因为你有c++17。https://gcc.godbolt.org/z/kJN7hu

#include<type_traits>
template<class... Types>
struct TypeContainer{
template<class T>
using contains = typename std::disjunction< std::is_same<T,Types>... >::type;
};
using allowed_types = TypeContainer<
int, 
float
>;
template<class T, typename = std::enable_if_t<allowed_types::contains<T>::value>>
void compute(const T& t);
void foo() {
int i;
compute(i);
//char c; compute(c);
}

然而,这似乎有点麻烦。我必须准备

template<class T, template<class> class C = is_good, typename = check_constraints<C, T>>

到我计划通用化的所有函数。

有更好的方法吗?

我认为C风格的宏是邪恶的,但对于这样的问题,我认为用于该模板签名的宏是合理的。

不管怎样,我建议局部改进一下。

使用您的实际函数样式,在默认模板模板参数(C)之前使用可推导类型(T)

template<class T, template<class> class C = is_good,
typename = check_constraints<C, T>>
void compute(const T& t) {}

如果要显式显示不同于默认模板参数(is_good)的模板模板参数,则必须显式显示可推导类型和模板模板参数

compute<B<double, 2, 3>, is_good_i_hope>(B<double, 2, 3>);

失去了从函数自变量中推导CCD_ 12。

但是,如果您在可推导类型之前表达模板模板参数

template <template<typename> class C = is_good, typename T,
typename = check_constraints<C, T>>
void compute (T const &)
{ } 

当您想要显式一个不同于默认的模板模板参数时,您只能显式C

compute<is_good_i_hope>(B<double, 2, 3>);

维持CCD_ 14的推导。

一旦你有了自己的特征,你可以简单地使用SFINAE:

template<class T>
std::enable_if_t<is_good<T>>
compute(const T& t) {}

template<class T, std::enable_if_t<is_good<T>, int> = 0>
void compute(const T& t) {}
相关文章: