为什么模板化类的模板化typef是无效语法

Why is a templated typef of a templated class invalid syntax?

本文关键字:无效 语法 为什么 typef      更新时间:2023-10-16

使用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具有某种类型,然后可以对其进行转换。下面将详细解释它的工作原理,包括完整的代码片段。

如果这个问题措辞不好或难以理解,请帮助我改进。这是我一直在研究的最复杂的模板问题之一。英语不是我的母语。


为什么疯狂

作为一个练习,我想编写一个模板构造,使我能够调用printf和类似的函数,这些函数需要char[] s和std::string s。

为此,我必须遍历每一个参数,并专门研究它可能是std::string的情况。为了做到这一点,我有一个结构fwd<typename func_t, typename ... LeftArgs>,它包含所有已处理的参数,在它内部有一个one_arg<typename Arg, typename ... RightArgs>,它允许通过专门处理空的基本情况和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 ...);
    }
};

我希望结构是显而易见的。如果没有,这里是整个片段,准备好了。

完整片段:

#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...);
}

nextA是一个依赖范围,因此需要指出B是模板的名称:

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

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

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

有关血腥的细节,请参阅"我必须在哪里以及为什么要放";模板";以及";typename";关键词?