Bas*_*tch 12 c++ variadic-templates c++11
以下代码
#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}); }
Run Code Online (Sandbox Code Playgroud)
正在编译(使用GCC 6.3,在Debian/Sid/x86-64上),我希望它可以像
auto vec = make_from_ints(1,2,3);
Run Code Online (Sandbox Code Playgroud)
返回指向包含1,2,3的整数向量的指针.
但是,如果我替换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}); }
Run Code Online (Sandbox Code Playgroud)
我收到编译错误:
basiletemplates.cc:8:17: error: ‘double’ is not a valid type
for a template non-type parameter
template<double ...>
^~~
Run Code Online (Sandbox Code Playgroud)
而且我不明白为什么.毕竟这两个int和double是标数值POD类型(在C++ 11标准的预定义).
如何获得模板可变函数以便能够编码:
auto dvec = make_from_doubles(-1.0, 2.0, 4.0);
Run Code Online (Sandbox Code Playgroud)
并获得一个指向包含-1.0,2.0,4.0的双精度矢量的指针?
BTW,编译C++ 14(带g++ -Wall -std=c++14 -c basiletemplates.cc)和使用clang++(版本3.8.1)而不是g++改变任何东西.
Vit*_*meo 23
template<int ...>
const std::vector<int>*make_from_ints(int args...)
{ return new std::vector<int>(std::initializer_list<int>{args}); }
Run Code Online (Sandbox Code Playgroud)
上面的代码段有很多问题:
返回a const std::vector<int>*而不是std::vector<int>不必要地使用动态分配.
std::make_unique而不是new.您定义make_from_ints为模板函数,它接受任意数量的int模板参数,但您没有给出这些int名称 - 您不能使用它们!
您的签名实际上被解析为make_from_ints(int args, ...)- 这是一个va_args与可变参数模板无关的C 签名.
type... name.如果你想接受任何特定类型的参数,这些参数与模板参数推导很有效,最简单的方法是使用一个常规的可变参数模板,它接受任意数量的类型和static_assert类型(或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...};
}
Run Code Online (Sandbox Code Playgroud)
用法:
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 << " ";
Run Code Online (Sandbox Code Playgroud)
1 2 3 4
1 1.5 2 2.5
请注意,我正在使用C++ 17 折叠表达式来检查是否所有Ts...类型都是特定类型:
static_assert((std::is_same<Ts, int>::value && ...));
Run Code Online (Sandbox Code Playgroud)
如果您无法访问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>{}...));
Run Code Online (Sandbox Code Playgroud)