特定类型的可变参数模板

Zac*_*Saw 17 c++ gcc variadic-templates c++11

我想要一个简单接受无符号整数的可变参数模板.但是,我无法让以下工作.

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);
}
Run Code Online (Sandbox Code Playgroud)

任何帮助赞赏.

编辑:如果你想知道,我正在尝试使用可变参数模板来复制以下内容.

struct Array
{
    Array(unsigned size1) { ... }
    Array(unsigned size1, unsigned size2) { ... }
    Array(unsigned size1, unsigned size2, unsigned size3) { ... }
    // ...
    Array(unsigned size1, unsigned size2, ..., unsigned sizeN) { ... }
};
Run Code Online (Sandbox Code Playgroud)

Lil*_*ard 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...
    }
};
Run Code Online (Sandbox Code Playgroud)


Ker*_* SB 5

如果要接受必须全部为整数的动态参数,则需要普通的typename模板,但要检查所有类型是否(可转换为)无符号整数:

#include <type_traits>

struct Array
{
    template <typename ...Args>
    explicit Array(Args ...args,
        typename std::enable_if<all_int<Args...>::value>::type * = nullptr);

    // ...
};
Run Code Online (Sandbox Code Playgroud)

现在你只需要特质:

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>
{ }
Run Code Online (Sandbox Code Playgroud)

如果您希望使类型严格,您也可以使用is_same而不是is_convertible.

另一种选择是完全放弃可变参数模板,并通过接受单个列表使列表可以初始化std::initializer_list<unsigned int>,这提供了更好的数字安全性(例如,禁止缩小转换).

  • 列表初始化是阻止缩小转换的原因,这对于`std :: initializer_list`并不特殊.另外,OP基本上需要`Array(unsigned ... args)`.并且它不是关于他们能够转换为`unsigned`,而是关于他们已经*'无符号`所以他没有在ctor内的列表初始化中缩小转换. (3认同)

Ola*_*che 5

查看初始化列表

你可以指定它像

struct Array
{
    Array(std::initializer_list<unsigned> sizes)
    {
        for (auto i = sizes.begin(); i != sizes.end(); ++i)
            ...
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然,用法会更改为

Array arr = {1, 1};
Run Code Online (Sandbox Code Playgroud)