命名空间和类中的可变参数模板函数

ptrlukas

我在类中定义了三个可变参数模板函数作为静态方法。比我决定将它们移到名称空间。当类解决方案按预期方式编译和运行时,命名空间方法无法编译。

这是基于工人阶级的解决方案:

#include <list>
#include <string>

class sample
{
public:
    template<typename T>
    static std::string encode(T t) {
        /* do something useful with t */
        return std::string("encoded value");
    }

    template<typename... Ts>
    static std::string encode(Ts... ts) {
        std::list<std::string> values;
        return encode(values, ts...);
    }

    template<typename T, typename... Ts>
    static std::string encode(std::list<std::string>& values, T t, Ts... ts) {
        values.push_back(encode(t));
        return encode(values, ts...);
    }
};

这是名称空间内的类似定义:

#include <list>
#include <string>

namespace sample
{
    template<typename T>
    std::string encode(T t) {
        /* do something useful with t */
        return std::string("encoded value");
    }

    template<typename... Ts>
    std::string encode(Ts... ts) {
        std::list<std::string> values;
        return encode(values, ts...);
    }

    template<typename T, typename... Ts>
    std::string encode(std::list<std::string>& values, T t, Ts... ts) {
        values.push_back(encode(t));
        return encode(values, ts...);
    }
};

在这两种情况下,均可通过以下方式使用编码

std::string encoded = sample::encode(1, 2u, 3.0);

命名空间方法失败,并出现以下错误(缩短了第一行):

sample_namespace.hpp: In instantiation of ‘std::__cxx11::string sample::encode(Ts ...) [with Ts = {std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, ...
sample_namespace.hpp:18:22:   recursively required from ‘std::__cxx11::string sample::encode(Ts ...) [with Ts = {std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, int, unsigned int, double}]’
sample_namespace.hpp:18:22:   required from ‘std::__cxx11::string sample::encode(Ts ...) [with Ts = {int, unsigned int, double}]’
sample_namespace.hpp:17:32: fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum)
     std::list<std::string> values;
                            ^~~~~~
compilation terminated.

明确定义encode(int,uint,double)时,会发生相同的错误:

template std::string sample::encode<int, uint, double>(int a, uint b, double c);

当给出单个参数时,第一个模板被使用encode(T t)并进行代码编译。

为什么放置在名称空间中的模板会失败?

上面的代码不是(不是)用gcc 6.4.0 x86_64编译的。我还尝试使用启用的C ++ 14和C ++ 17进行编译。
代码也无法通过godbolt.org进行gcc 7.3,clang 6.0.0和icc 18的编译

斯蒂芬·纽厄尔

只需要动一个可变template的形式encode非可变参数之前template的形式。当您处理非成员函数时,顺序要比对成员函数重要得多。Godbolt接受以下内容:

#include <list>
#include <string>

namespace sample
{
    template<typename T>
    std::string encode(T t) {
        /* do something useful with t */
        return std::string("encoded value");
    }

    template<typename T, typename... Ts>
    std::string encode(std::list<std::string>& values, T t, Ts... ts) {
    values.push_back(encode(t));
        return encode(values, ts...);
    }

    template<typename... Ts>
    std::string encode(Ts... ts) {
        std::list<std::string> values;
        return encode(values, ts...);
    }
};

std::string do_it() {
    return sample::encode(1, 2u, 3.0);
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在SWIG中包装可变参数模板类的可变参数模板成员函数?

可变参数模板类中的派生(虚拟)函数参数

限制可变参数模板类中的构造函数访问

可变参数模板类和调用构造函数中的多重继承

SFINAE和可变参数模板类

可变参数模板类-可变参数成员函数

可变参数模板中的函数顺序

可变参数函数和可变参数模板重载查找

从模板化模板类和可变参数模板中声明“容器”对象

如何检查类型是否从模板函数中的某个可变参数模板类实例化?

如何在非变量模板类中形成可变参数模板函数?

使用可变参数类模板的模板参数调用可变参数函数模板?

可变参数模板类的可变参数模板

可变参数模板与类中的函数参数数量相同

可变参数模板函数参数和引用类型推导

具有左值和右值的可变参数模板类构造函数

调用类内的函数的C ++ 11可变参数模板

如何访问可变参数模板函数中的参数

C ++中没有参数可变参数模板函数

在可变参数模板类的构造函数中初始化元组成员

从类模板中提取模板模板参数和可变参数模板参数

配对的可变参数模板(命名元组)

C ++:可变参数模板和函数重载

以可变参数类模板作为函数调用参数的函数模板参数推导

可变参数模板类中的定义数量不同

clang不使用可变参数推断可变参数模板函数中的模板参数

用可变参数模板在C ++中包装函数指针

可变参数模板扩展中的函数调用顺序

组合策略类-模板模板参数和可变参数模板