boost::enable_if不在函数签名中
boost::enable_if not in function signature
这只是一个关于风格的问题:我不喜欢C++用于模板元编程的方式,它要求您使用返回类型或为SFINAE的技巧添加额外的伪参数。所以,我想到的想法是把SFINAE的东西放在模板参数定义本身中,就像这样:
#include <iostream>
#include <boost/type_traits/is_array.hpp>
#include <boost/utility/enable_if.hpp>
using namespace std;
template <typename T, typename B=typename boost::enable_if< boost::is_array<T> >::type > void asd(){
cout<<"This is for arrays"<<endl;
}
template <typename T, typename B=typename boost::disable_if< boost::is_array<T> >::type > void asd(){
cout<<"This is for NON arrays"<<endl;
}
int main() {
asd<int>();
asd<int[]>();
}
这个例子让g++抱怨:
/src/afg.cpp:10:97:错误:重新定义"template void asd()"
SFINAE本身是有效的,因为如果我删除例如带有disable_if
的那个,编译器错误是:
/src/afg.cpp:15:12:error:调用"asd()"时没有匹配的函数
这就是我想要的。
那么,有没有一种方法可以在函数的"正常"签名中实现SFINAE,即返回类型+参数列表?
编辑:这就是我最终要在真实代码中尝试的内容:
#include <iostream>
#include <type_traits>
using namespace std;
template <typename T, typename enable_if< is_array<T>::value, int >::type =0 > void asd(){
cout<<"This is for arrays"<<endl;
}
template <typename T, typename enable_if< !is_array<T>::value, int >::type =0 > void asd(){
cout<<"This is for NON arrays"<<endl;
}
int main() {
asd<int[]>();
asd<int>();
}
我使用c++0x而不是boost,因为只要我需要c++0x来使用模板参数的默认值,我就没有理由使用boost,这是它的前身。
好吧,我通常使用这些宏来使enable_if结构更干净(它们甚至在大多数C++03编译器中都能工作):
#define ERROR_PARENTHESIS_MUST_BE_PLACED_AROUND_THE_RETURN_TYPE(...) __VA_ARGS__>::type
#define FUNCTION_REQUIRES(...) typename boost::enable_if<boost::mpl::and_<__VA_ARGS__, boost::mpl::bool_<true> >, ERROR_PARENTHESIS_MUST_BE_PLACED_AROUND_THE_RETURN_TYPE
#define EXCLUDE(...) typename boost::mpl::not_<typename boost::mpl::or_<__VA_ARGS__, boost::mpl::bool_<false> >::type >::type
然后你可以这样定义你的函数:
template <typename T >
FUNCTION_REQUIRES(is_array<T>)
(void) asd(){
cout<<"This is for arrays"<<endl;
}
template <typename T >
FUNCTION_REQUIRES(EXCLUDE(is_array<T>))
(void) asd(){
cout<<"This is for NON arrays"<<endl;
}
唯一的问题是,您需要在返回类型周围加上括号。如果忘记了它们,编译器会说"ERROR_PARENTHESIS_MUST_BE_PLACED_ARUND_the_RETURN_TYPE"未定义。
由于C++11使它成为可能,我只在模板参数中使用enable_if
(或者相反地使用disable_if
),就像您现在所做的那样。如果/当有几个重载时,我会使用伪的默认模板参数,这会使模板参数列表的arity不同。因此,为了重用您的示例,将是:
template<
typename T
, typename B = typename boost::enable_if<
boost::is_array<T>
>::type
>
void asd() {
cout << "This is for arrays" << endl;
}
template<
typename T
, typename B = typename boost::disable_if<
boost::is_array<T>
>::type
, typename = void
>
void asd() {
cout << "This is for arrays" << endl;
}
另一种不扰乱返回类型(在某些情况下不可用,例如转换运算符)的方法是使用默认参数:
template<typename T>
void
foo(T t, typename std::enable_if<some_trait<T>::value>::type* = nullptr);
我不使用这种形式,因为我不喜欢和返回类型一样"搅乱"参数类型,而且出于一致性的原因(因为这在所有情况下都不可行)。
默认模板参数不是函数模板签名的一部分。但是模板参数的类型是。所以你可以做以下操作,并能够重载它
template <
typename T,
typename boost::enable_if<
boost::is_array<T>, int
>::type = 0
>
void asd() {
cout<<"This is for arrays"<<endl;
}
template <
typename T,
typename boost::disable_if<
boost::is_array<T>, int
>::type = 0
>
void asd() {
cout<<"This is for arrays"<<endl;
}
这可能不是你想要的,但好的旧模板专业化怎么样?
template<typename T>
struct asd
{
static void fgh()
{
std::cout << "not an arrayn";
}
};
template<typename T>
struct asd<T[]>
{
static void fgh()
{
std::cout << "an array of unknown sizen";
}
};
template<typename T, size_t N>
struct asd<T[N]>
{
static void fgh()
{
std::cout << "an array of known sizen";
}
};
int main()
{
asd<int>::fgh();
asd<int[]>::fgh();
asd<int[42]>::fgh();
}
那么,有没有一种方法可以在函数的"正常"签名中实现SFINAE,即返回类型+参数列表?
好吧,有一种方法可以在根本不使用SFINAE的情况下获得相同的结果—过载:
#include <iostream>
#include <type_traits>
void asd_impl(std::true_type&&)
{
std::cout << "This is for arraysn";
}
void asd_impl(std::false_type&&)
{
std::cout << "This is not for arraysn";
}
template<typename T>
void asd()
{
asd_impl(std::is_array<T>());
}
int main()
{
asd<int>();
asd<int[]>();
}
这种风格的可读性要高得多,并且在BoostSpirit等模板密集型库中广泛使用,因为它往往编译得更快,并且与支持不太出色的模板/SFINAE的编译器(例如VC++和Sun Studio)配合得更好。
在线演示。
- "error: no matching function for call to"构造函数错误
- 什么时候调用组成单元对象的析构函数
- 继承函数的重载解析
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- C++模板来检查友元函数的存在
- 递归函数计算序列中的平方和(并输出过程)
- 对RValue对象调用的LValue ref限定成员函数
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么使用 "this" 指针调用派生成员函数?
- 将对象数组的引用传递给函数
- 函数调用中参数的顺序重要吗
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用不带参数的函数访问结构元素
- 代码在main()中运行,但在函数中出现错误
- 内置函数可查看CPP中的成员变量
- 如何获取std::result_of函数的返回类型
- 如何在c++中为模板函数实例创建快捷方式
- 如何"enable"基于模板参数的函数?