强制使用某种类型的可变参数模板

Ger*_*ard 18 c++ templates variadic-templates c++11

我想强制使用可变参数模板的类型与先前设置的模板类型相同.在下面的例子中,我希望T和U是相同的类型.

ideone.com上的代码

#include <iostream>
#include <string>

template<class T>
struct Foo {

    Foo(T val) {
        std::cout << "Called single argument ctor" << std::endl;
        // [...]    
    }    

    // How to enforce U to be the same type as T?
    template<class... U>
    Foo(T first, U... vals) {
        std::cout << "Called multiple argument ctor" << std::endl;
        // [...]   
    }

};

int main() {

    // Should work as expected.
    Foo<int> single(1);

    // Should work as expected.
    Foo<int> multiple(1, 2, 3, 4, 5);

    // Should't work (but works right now). The strings are not integers.
    Foo<int> mixedtype(1, "a", "b", "c");

    // Also shouldn't work. (doesn't work right now, so that is good)
    Foo<int> alsomixedtype(1, 1, "b", "c");
}
Run Code Online (Sandbox Code Playgroud)

Tar*_*ama 12

我们可以使用SFINAE来确保所有U类型都相同T.需要注意的一件重要事情是,U不仅仅是您所暗示的一种类型,而是可能不同类型的列表.

template<class... U, std::enable_if_t<all_same<T, U...>::value>* = nullptr>
Foo(T first, U... vals) {
    std::cout << "Called multiple argument ctor" << std::endl;
    // [...]   
}
Run Code Online (Sandbox Code Playgroud)

std::enable_if_t来自C++ 14.如果这不适合您,请使用std::enable_if.

typename std::enable_if<all_same<T, U...>::value>::type* = nullptr>
Run Code Online (Sandbox Code Playgroud)

all_same可以用一堆不同的方式实现.这是我喜欢使用布尔包的方法:

namespace detail
{
    template<bool...> struct bool_pack;
    template<bool... bs>
    //if any are false, they'll be shifted in the second version, so types won't match
    using all_true = std::is_same<bool_pack<bs..., true>, bool_pack<true, bs...>>;
}
template <typename... Ts>
using all_true = detail::all_true<Ts::value...>;

template <typename T, typename... Ts>
using all_same = all_true<std::is_same<T,Ts>...>;
Run Code Online (Sandbox Code Playgroud)

  • 您不必再在 C++17 中实现 `all_same`,因为它有 `std::conjunction` /sf/answers/3565742141/ (2认同)

Dev*_*ull 5

std::conjunction(逻辑与)是在 C++17 中引入的,因此不必再all_same手动实现。然后构造函数变得简单:

template<typename... U,
    typename = std::enable_if_t<
        std::conjunction_v<
            std::is_same<T, U>...
        >
    >
>
Foo(T first, U... vals)
{
    std::cout << "Called multiple argument ctor" << std::endl;
    // [...]   
}
Run Code Online (Sandbox Code Playgroud)

请参阅现场示例