【发布时间】:2014-10-07 01:33:17
【问题描述】:
使用 MSVC12,我在尝试 typedef 依赖类型名时遇到奇怪的语法错误,如下所示:
template <typename ... LeftT>
struct A{
template <typename ...>
struct B{};
template <typename T, typename ... RightT>
struct B <T, RightT ... >{
typedef typename A<LeftT ..., T> nextA;
typedef typename nextA::B<RightT ...> nextB; //error C2059: syntax error : '<'
};
};
这就是它的全部内容,模板从不实例化,除非在其内部。
我的问题:为什么会出现语法错误?这是无效的语法吗?
你问(可能):你为什么要这样做?
基本思想是通过类型转换进行转发。这将通过专门化B 来完成,以便T 属于某种类型,然后可以对其进行转换。下面详细解释了它的工作原理,包括完整的代码 sn-p。
如果这个问题措辞不好或难以理解,请帮助我改进它。这是我一直在研究的最复杂的模板问题之一 英语不是我的母语。
为什么这么疯狂?
作为一个练习,我想编写一个模板构造,允许我调用printf 和需要char[]s 和std::strings 的类似函数。
为此,我必须遍历每一个参数,并专门针对可能是std::string 的情况。为了做到这一点,我有一个结构fwd<typename func_t, typename ... LeftArgs>,它包含所有已处理的参数,在里面有一个结构one_arg<typename Arg, typename ... RightArgs>,它允许通过专门针对空基本情况和情况来处理当前参数Arg 是 std::string。基本情况(没有参数,或没有任何待处理)的处理方式如下:
template<typename ...>
struct one_arg
{
//implementation of return_type will be shown below
static return_type forward(func_t func, LeftArgs ... leftArgs){
return func(leftArgs ...); //execute function
}
};
特殊化基本情况是参数具有除std::string之外的任何类型的常见情况:
template<typename Arg, typename ... RightArgs>
struct one_arg < Arg, RightArgs ...>
{
//move Arg to the processed arguments
typedef typename fwd< func_t, LeftArgs..., Arg>::one_arg<RightArgs...> next_arg;
static return_type forward(func_t func, LeftArgs ... leftArgs, Arg arg, RightArgs ... rightArgs){
return next_arg::forward(func, leftArgs ..., arg, rightArgs ...);
}
};
用几乎相同的语法进一步特化这种常见情况,即当前参数确实是std::string类型的情况:
template<typename ... RightArgs>
struct one_arg < std::string, RightArgs ...>
{
//again, move Arg to the processed arguments, but as a char[]
typedef typename fwd< func_t, LeftArgs..., char[]>::one_arg<RightArgs...> next_arg;
static return_type forward(func_t func, LeftArgs ... leftArgs, std::string arg, RightArgs ... rightArgs){
//convert string to char[]
return next_arg::forward(func, leftArgs ..., arg.c_str(), rightArgs ...);
}
};
我希望结构是显而易见的。如果没有,这里是整个 sn-p,准备好了。
完成sn-p:
#include <string>
using namespace std;
//get the return type of a function
template <typename T>
struct get_return_type;
template <typename R, typename ... A>
struct get_return_type<R(A...,...)>
{
typedef R type;
};
template<typename func_t, typename ... LeftArgs>
struct fwd{
typedef typename get_return_type<func_t> return_type;
//empty base case
template<typename ...>
struct one_arg
{
static return_type forward(func_t func, LeftArgs ... leftArgs){
return func(leftArgs ...);
}
};
//normal forwarding
template<typename Arg, typename ... RightArgs>
struct one_arg < Arg, RightArgs ...>
{
typedef typename fwd< func_t, LeftArgs..., Arg>::one_arg<RightArgs...> next_arg;
static get_return_type<func_t> forward(func_t func, LeftArgs ... leftArgs, Arg arg, RightArgs ... rightArgs){
return next_arg::forward(func, leftArgs ..., arg, rightArgs ...);
}
};
//specialisation for std::string
template<typename ... RightArgs>
struct one_arg < std::string, RightArgs ...>
{
typedef typename fwd< func_t, LeftArgs..., char[]>::one_arg<RightArgs...> next_arg;
static get_return_type<func_t> forward(func_t func, LeftArgs ... leftArgs, std::string arg, RightArgs ... rightArgs){
return next_arg::forward(func, leftArgs ..., arg.c_str(), rightArgs ...);
}
};
};
template<typename func_t, typename ... Args>
typename fwd<func_t>::one_arg<Args ...>::return_type forward_stoc(func_t func, Args ... args){
typedef typename fwd<func_t>::one_arg<Args ...> next_arg;
return next_arg::forward(func, args...);
}
【问题讨论】:
-
我不知道缺少关键字,所以我认为这不是重复问题,而不是相关问题。
-
在符合标准的编译器中,第一个不应该有
typename,第二个需要template。不过,我不知道 MSVC。 -
@T.C.没错,第一个不需要
typename。我不知道template关键字可以而且需要这样使用。 -
@iFreilicht:这个问题准确地解释了您需要这些关键字的位置和原因,因此回答了这个问题(以及一般涉及依赖范围的问题)。对于您的具体问题,我也给出了一个简单的答案。
-
@MikeSeymour 这是真的,我很感谢你的回答,但我的问题在我眼里之前没有被问过。
标签: c++ templates c++11 type-conversion variadic-templates