我想要一个简单接受无符号整数的可变参数模板。 但是,我无法让以下工作。
struct Array
{
template <typename... Sizes> // this works
// template <unsigned... Sizes> -- this does not work (GCC 4.7.2)
Array(Sizes... sizes)
{
// This causes narrowing conversion warning if signed int is supplied.
unsigned args[] = { sizes... };
// ...snipped...
}
};
int main()
{
Array arr(1, 1);
}
任何帮助表示感谢。
编辑:如果您想知道,我正在尝试使用可变参数模板来复制以下内容。
struct Array
{
Array(unsigned size1) { ... }
Array(unsigned size1, unsigned size2) { ... }
Array(unsigned size1, unsigned size2, unsigned size3) { ... }
// ...
Array(unsigned size1, unsigned size2, ..., unsigned sizeN) { ... }
};
答案 0 :(得分:5)
我不确定你为什么要这样做。 Clang告诉我构造函数声明中的错误是unknown type name 'Sizes'
。这是预期的,因为Sizes
不是类型(或者更确切地说,类型的模板包),它是值的模板包。
目前还不清楚你到底想要做什么。如果在模板参数中传递整数值,那么构造函数参数应该是什么?
更新:使用新代码,您只需static_cast<unsigned>()
。
struct Array
{
template <typename... Sizes> // this works
Array(Sizes... sizes)
{
unsigned args[] = { static_cast<unsigned>(sizes)... };
// ...snipped...
}
};
答案 1 :(得分:5)
如果要接受必须全部为整数的动态参数,则需要普通的 typename 模板,但检查所有类型是否(可转换为)无符号整数:
#include <type_traits>
struct Array
{
template <typename ...Args>
explicit Array(Args ...args,
typename std::enable_if<all_int<Args...>::value>::type * = nullptr);
// ...
};
现在你只需要这个特性:
template <typename...> struct all_int;
template <> struct all_int<> : std::true_type { };
template <typename T, typename ...Rest> struct all_int<T, Rest...>
: std::integral_constant<bool,
std::is_convertible<T, unsigned int>::value && all_int<Rest>::value>
{ }
如果您希望严格使用类型,则还可以使用is_same
代替is_convertible
。
另一种选择是完全放弃可变参数模板,并通过接受单个std::initializer_list<unsigned int>
使您的类列表可初始化,这提供了更好的数字安全性(例如,禁止缩小转换)。
答案 2 :(得分:2)
您可以将其指定为
struct Array
{
Array(std::initializer_list<unsigned> sizes)
{
for (auto i = sizes.begin(); i != sizes.end(); ++i)
...
}
}
虽然,使用情况会改为
Array arr = {1, 1};
答案 3 :(得分:1)
当试图或多或少地实现OP所要做的事情时,我偶然发现了这个相当老的问题。我已经实现了类似于@Kerrek SB解决方案的方法,并且正在寻找一种“一般化”此行为的方法(通过提供谓词作为模板结构来进行评估,而不必为不同的谓词重新实现“递归” )。 但是,在这样做的同时,我意识到新的CPP20 Concepts功能以一种非常优雅的方式解决了该问题,因此希望共享该解决方案。我没有将概念视为解决方案,因为我在某处读到不能以递归的方式声明它们(据我发现,这不是实际的负担,因为我可以引用递归类型特征解决方案)。
在此解决方案中,我定义了一个自定义概念,因为我认为STL提供的概念并不涵盖大多数实际用例,在这种情况下可以使用这些用例。只需将使用的概念替换为“类型名称”,该概念就会应用于所有提供的模板参数。
#include <concepts>
#include <type_traits>
template <typename T> concept unsignedType = std::is_unsigned_v<T>;
struct Array {
template <unsignedType... Sizes> Array(Sizes... sizes) {
unsigned args[] = {sizes...};
}
};
int main() {
unsigned k = 12;
Array arr(k, 1u);
//Array arr(33); // fails as 33 is not unsigned
}
我使用的是gcc-10,在以前的版本中,概念功能可能不可用,因为该功能是实验性的: g ++-10.0 -std = c ++ 2a file.cc