宏使用 GCC 编译,但不使用 VS11 编译
Macro compiles with GCC but not with VS11
我编写了以下代码来帮助将模板函数限制为某些类型,并在使用其他类型的时显示有意义的错误消息。我的想法来自stackoverflow中的一个不同问题,我仍然无法对此发表评论,因为我是新来的。
该宏在Linux GCC下完美编译,但在Visual Studio 2012下则不然。
#include <string>
#include <iostream>
#include <vector>
#include <cassert>
#include <type_traits>
#define ISALLOWED(DerivedT) (std::is_same<T, DerivedT>::value)||(std::is_base_of<T,DerivedT>::value)
#define FE_1(WHAT, X) WHAT(X)
#define FE_2(WHAT, X, ...) WHAT(X) || FE_1(WHAT, __VA_ARGS__)
#define FE_3(WHAT, X, ...) WHAT(X) || FE_2(WHAT, __VA_ARGS__)
#define FE_4(WHAT, X, ...) WHAT(X) || FE_3(WHAT, __VA_ARGS__)
#define FE_5(WHAT, X, ...) WHAT(X) || FE_4(WHAT, __VA_ARGS__)
#define FE_6(WHAT, X, ...) WHAT(X) || FE_5(WHAT, __VA_ARGS__)
//... repeat as needed
#define GET_MACRO(_1,_2,_3,_4,_5,_6,NAME,...) NAME
#define FOR_EACH(action,...)
GET_MACRO(__VA_ARGS__,FE_6,FE_5,FE_4,FE_3,FE_2,FE_1)(action,__VA_ARGS__)
// this is where you need to add types
#define ASSERTIOTYPES
static_assert(FOR_EACH(ISALLOWED,
int,double,std::string
),"Type not defined for this template.");
template<class T> std::ostream & operator<<(std::ostream &os,
const std::vector<T> & v) {
ASSERTIOTYPES;
os << "[";
for (size_t i = 0; i < v.size(); i++) {
os << v[i];
if (i != v.size() - 1)
os << ", ";
}
os << "]";
return os;
}
错误消息是:错误 C2977:"std::is_same":模板参数过多
仅当我使用多个类型定义 ASSERTIOTYPE 时,但仅使用一种类型定义它时,它才会出现,例如:
#define ASSERTIOTYPES
static_assert(FOR_EACH(ISALLOWED,
int
),"Type not defined for this template.");
。代码正常编译。
知道如何解决这个问题吗?
template<typename T> struct is_io_type : std::false_type {};
template<> struct is_io_type<int> : std::true_type {};
template<> struct is_io_type<double> : std::true_type {};
template<> struct is_io_type<std::string> : std::true_type {};
然后,只需键入以下内容,而不是宏:
static_assert( is_io_type<T>::value, "Type not defined for this template." )
这大约是冗长的,而不是那么晦涩难懂或难以弄清楚到底发生了什么。
现在,假设我们确实需要is_base_of
功能。
template<typename T,typename=void> struct is_io_type : std::false_type {};
template<> struct is_io_type<int,void> : std::true_type {};
template<typename T> struct is_io_type<T,typename std::enable_if<std::is_base_of<int, T>::type> : std::true_type {};
template<> struct is_io_type<double,void> : std::true_type {};
template<typename T> struct is_io_type<T,typename std::enable_if<std::is_base_of<double, T>::type> : std::true_type {};
template<> struct is_io_type<std::string,void> : std::true_type {};
template<typename T> struct is_io_type<T,typename std::enable_if<std::is_base_of<std::string, T>::type> : std::true_type {};
这变得非常冗长。
但是,与其在使用宏时创建可变宏展开,不如使用宏来构建上述类型特征特化。
因此,您首先创建类型特征,然后扩展它:
CREATE_TYPE_CATEGORY( is_io_type );
ADD_BASE_TYPE_CATEGORY( is_io_type, int );
ADD_BASE_TYPE_CATEGORY( is_io_type, double );
ADD_BASE_TYPE_CATEGORY( is_io_type, std::string );
这会不那么冗长地编写上面的代码。 它还支持分布式特征修改:如果有人创建了一个应该is_io_type
的新类型,他们可以在引入类型后使用上面的宏,它(及其后代)成为io类型。
从您描述的问题来看,这很可能是VA_ARGS的错误
我建议你要么使用静态内联,要么你可以写一个简单的测试。复制上面的大部分代码并检查GET_MACRO给你什么。然后,您可以发布结果,这将对进一步诊断非常有帮助。