这只是一个关于风格的问题:我不喜欢 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:错误:重新定义“模板 void asd()”
SFINAE 本身可以工作,因为如果我删除例如带有 disable_if
的那个,编译器错误是:
../src/afg.cpp:15:12:错误:没有匹配的函数可用于调用“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,这是它的前身。
This is just a question about style: I don't like the way of C++ for template metaprogramming that requires you to use the return type or add an extra dummy argument for the tricks with SFINAE. So, the idea I came up with is to put the SFINAE thing in the template arguments definition itself, like this:
#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[]>();
}
This example make g++ complain:
../src/afg.cpp:10:97: error: redefinition of ‘template void asd()’
SFINAE there itself works, because if I delete for example the one with disable_if
, the compiler error is:
../src/afg.cpp:15:12: error: no matching function for call to ‘asd()’
Which is what I want.
So, is there a way to accomplish SFINAE not in the "normal" signature of a function, that is return type + argument list?
EDIT:
This is in the end what I'm going to try in the real code:
#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>();
}
I use c++0x stuff instead of boost because as long as I need c++0x for using defaults of template arguments, I see no reason to use boost, which is its precursor.
发布评论
评论(5)
嗯,我通常使用这些宏来使enable_if构造更干净(它们甚至可以在大多数C++03编译器中工作):
然后你可以像这样定义你的函数:
唯一的事情是,你需要在返回类型两边加上括号。如果您忘记了它们,编译器会说“ERROR_PARENTHESIS_MUST_BE_PLACED_AROUND_THE_RETURN_TYPE”未定义之类的内容。
Well, I generally use these macros to make enable_if constructs a lot cleaner(they even work in most C++03 compilers):
Then you would define your function like this:
The only thing is, you need to put parenthesis around the return type. If you forget them, the compiler will say something like 'ERROR_PARENTHESIS_MUST_BE_PLACED_AROUND_THE_RETURN_TYPE' is undefined.
由于 C++11 使其成为可能,我只在模板参数中使用
enable_if
(或相反disable_if
),就像您所做的那样。如果/当有多个重载时,我会使用虚拟的默认模板参数,这使得模板参数列表的数量不同。因此,要重用您的示例,那就是:自 C++03 以来就存在的不弄乱返回类型(在某些情况下不可用,例如转换运算符)的另一种替代方法是使用默认参数:
我不使用这个因为我不喜欢对参数类型进行“混乱”,就像对返回类型进行“混乱”一样,并且出于一致性原因(因为这并非在所有情况下都是可行的)。
Since C++11 made it possible, I only ever use
enable_if
(or converselydisable_if
) inside the template arguments, the way you're doing. If/when there are several overloads, then I use dummy, defaulted template arguments which makes the template parameter lists differ in arity. So to reuse your example that would be:Another alternative to not messing the return type (that is not available in some cases, e.g. conversion operators) that has existed since C++03 is to use default arguments:
I don't use this form as I dislike 'messing' with the argument types just as much as with the return type, and for consistency reasons (since that's not doable in all cases).
默认模板参数不是函数模板签名的一部分。但模板参数的类型是。所以你可以执行以下操作并能够重载它
Default template arguments are not part of the signature of function templates. But the type of template parameters is. So you can do the following and be able to overload it
这可能不完全是您所要求的,但是好的旧模板专业化怎么样?
This may not exactly be what you're asking for, but how about good old template specialization?
好吧,有一种方法可以在完全不使用 SFINAE 的情况下获得相同的结果 - 重载:在
我看来,这种风格的可读性要高得多,并且广泛用于模板密集型库,例如 Boost。Spirit 因为它倾向于编译速度更快,工作效果更好具有不太出色的模板/SFINAE 支持的编译器(例如 VC++ 和 Sun Studio)。
在线演示。
Well, there's a way to obtain the same result without using SFINAE at all — overloading:
This style is far more readable IMO, and is used extensively in template-heavy libraries such as Boost.Spirit because it tends to compile faster and works better with compilers having less-than-stellar template/SFINAE support (e.g. VC++ and Sun Studio).
Online demo.