【发布时间】:2013-12-01 15:31:46
【问题描述】:
我编写了以下代码来帮助将我的模板函数限制为某些类型,并在使用其他类型时显示有意义的错误消息。我从 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”:模板参数太多
只有当我用一种以上的类型定义 ASSERTIOTYPES 时,它才会出现,但是当它只用一种类型定义时,例如:
#define ASSERTIOTYPES \
static_assert(FOR_EACH(ISALLOWED,\
int\
),"Type not defined for this template.");
...代码编译正常。
知道如何解决这个问题吗?
【问题讨论】:
-
做高级预处理器的人认为 VS 预处理器严重损坏。如果可能的话,我建议你使用Boost.Preprocessor 而不是手写宏——它们涵盖了这些特性。
-
逗号分隔的标记序列扩展得太晚,导致宏替换期间的参数-参数匹配不正确。这个问题在
__VA_ARGS__的常见用法中尤其严重(比如这个)。您可以使用间接来解决错误行为。参见例如我展示的示例in an answer to another question。也就是说,Yakk 的解决方案是正确的解决方案;比使用宏更干净。
标签: c++ gcc visual-studio-2012 c++11 macros