带 double 的 C++ 可变参数模板

标签 c++ c++11 variadic-templates

以下代码

#include <initializer_list>
#include <vector>

template<int ...>
const std::vector<int>*make_from_ints(int args...)
{ return new std::vector<int>(std::initializer_list<int>{args}); }

正在正确编译(使用 GCC 6.3,在 Debian/Sid/x86-64 上),我希望它能像这样的调用

auto vec = make_from_ints(1,2,3);

返回一个指向包含 1、2、3 的整数 vector 的指针。

但是,如果我将 int 替换为 double,那就是如果我添加以下内容(在同一个 basiletemplates.cc 文件中...... .) 代码:

template<double ...>
const std::vector<double>*make_from_doubles(double args...)
{ return new std::vector<double>(std::initializer_list<double>{args}); }

我收到一个编译错误:

basiletemplates.cc:8:17: error: ‘double’ is not a valid type
                for a template non-type parameter
 template<double ...>
                 ^~~

我不明白为什么。毕竟 intdouble 都是标量数字 POD 类型(在 C++11 标准中预定义)。

如何获取模板可变参数函数以便能够编码:

auto dvec = make_from_doubles(-1.0, 2.0, 4.0);

并获得一个指向包含 -1.0, 2.0, 4.0 的 double vector 的指针?

顺便说一句,为 C++14 编译(使用 g++ -Wall -std=c++14 -c basiletemplates.cc),并使用 clang++(版本 3.8 .1) 而不是 g++ 不要改变任何东西。

最佳答案

template<int ...>
const std::vector<int>*make_from_ints(int args...)
{ return new std::vector<int>(std::initializer_list<int>{args}); }

上面的片段有很多问题:

  • 返回 const std::vector<int>*而不是 std::vector<int>并且不必要地使用动态分配。

    • 即使你想使用动态分配,你也应该使用 std::make_unique而不是 new .
  • 你定义了make_from_ints成为模板函数,可以使用任意数量的 int模板参数,但您没有提供这些 int s 一个名字 - 你永远不能使用它们!

  • 您的签名实际上被解析为 make_from_ints(int args, ...) - 这是一个 C va_args与可变参数模板无关的签名。

    • 参数包的正确语法是 type... name .

如果您想接受与 模板参数推导 配合得很好的特定类型的任意数量的参数,最简单的方法是使用接受的常规 可变参数模板任意数量的类型和static_assert s 他们的类型(或使用 std::enable_if 来为 SFINAE 友好)。这是一个例子:

template <typename... Ts>
auto make_from_ints(Ts... xs) 
{ 
    static_assert((std::is_same<Ts, int>::value && ...));
    return std::vector<int>{xs...};
}

template <typename... Ts>
auto make_from_doubles(Ts... xs) 
{ 
    static_assert((std::is_same<Ts, double>::value && ...));
    return std::vector<double>{xs...};
}

用法:

for(auto x : make_from_ints(1,2,3,4)) std::cout << x << " ";
std::cout << "\n";
for(auto x : make_from_doubles(1.0,1.5,2.0,2.5)) std::cout << x << " ";

1 2 3 4

1 1.5 2 2.5

live example on wandbox


请注意,我使用的是 C++17 fold expression检查是否所有 Ts...在这里属于特定类型:

static_assert((std::is_same<Ts, int>::value && ...));

如果您无法访问 C++17 功能,可以轻松地将其替换为以下内容:

template <typename... Ts>
constexpr auto all_true(Ts... xs)
{
    for(auto x : std::initializer_list<bool>{xs...}) 
        if(!x) return false;

    return true;
}

// ...

static_assert(all_true(std::is_same<Ts, int>{}...));

关于带 double 的 C++ 可变参数模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43180477/

相关文章:

c++ - 答案在不应该的时候四舍五入 C++

c++ - shmat 返回的指针指向地址空间的末尾,这会导致段错误

c++ - 具有 const 不可复制元素的元组

c++ - 访问各种类型的可变参数模板

c++ - Variadic 模板匹配 const 和非常量 std::string 时遇到问题

C++ 模板函数别名作为可变模板参数

c++ - 比较一个字符

c++ - 初始化 pthread 互斥锁

c++ - 从 map 中删除一个元素然后放回去

c++ - 比较C++中move和智能指针的习惯?