【问题标题】:Why is a templated typef of a templated class invalid syntax? [duplicate]为什么模板类的模板 typef 语法无效? [复制]
【发布时间】: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&lt;typename func_t, typename ... LeftArgs&gt;,它包含所有已处理的参数,在里面有一个结构one_arg&lt;typename Arg, typename ... RightArgs&gt;,它允许通过专门针对空基本情况和情况来处理当前参数Argstd::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


【解决方案1】:

nextA是一个依赖作用域,所以你需要指出B是一个模板的名字:

typedef typename nextA::template B<RightT ...> nextB;
                        ^^^^^^^^

请注意,nextA 的声明中不应有 typename,因为不涉及依赖范围:

typedef A<LeftT ..., T> nextA;

有关血腥细节,请参阅Where and why do I have to put the "template" and "typename" keywords?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-10
    • 1970-01-01
    • 1970-01-01
    • 2015-11-26
    • 1970-01-01
    • 2017-06-22
    • 1970-01-01
    相关资源
    最近更新 更多