可变构造函数中的SFINAE

Irg*_*why 2 c++ templates constructor variadic-templates c++17

我想定义一个通用的强别名类型,即一个类型

template<typename T, auto ID = 0>
class StrongAlias {
    T value;
};
Run Code Online (Sandbox Code Playgroud)

这样,对于类型Ta StrongAlias<T>可以以完全相同的方式使用T,但是StrongAlias<T, 0>并且StrongAlias<T, 1>是不能实现地相互转换的不同类型.为了T尽可能完美地模仿a ,我希望我StrongAlias拥有与之相同的构造函数T.这意味着我想做类似以下的事情:

template<typename T, auto ID = 0>
class StrongAlias {
    T value;
public:
    // doesn't work
    template<typename... Args, typename = std::enable_if_t<std::is_constructible_v<T, Args...>>>
    StrongAlias(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>)
        : value(std::forward<Args>(args)...) {}
};
Run Code Online (Sandbox Code Playgroud)

template parameter pack must be the last template parameter因为clang 5.0会告诉我,因为这不会起作用.我想到的另一种使用SFINAE的方法是返回类型,但由于构造函数没有返回类型,所以这似乎也不起作用.

有没有办法在构造函数中的可变参数模板参数包上使用SFINAE?

或者,如果没有,我可以用另一种方式完成我想要的吗?

请注意,T在我的情况下,从a中隐式构造是不够的,如show 的例子StrongAlias<std::optional<int>>:如果StrongAlias只能从a中隐含地构造,则不能std::optional<int>std::nullopt(类型std::nullopt_t)构造,因为这将涉及2个用户定义转换.我真的想拥有别名类型的所有构造函数.

编辑:当然可以在没有SFINAE的情况下实现它,如果a StrongAlias是由不兼容的参数构造的,那么程序就无效了.然而,虽然这在我的特定情况下是可接受的行为,但它显然不是最佳的,因为StrongAlias可以在模板中使用查询给定类型是否可从某些参数(via std::is_constructible)构造.虽然这会产生一个std::false_typefor T,但它会导致std::true_typefor StrongAlias<T>,这可能意味着StrongAlias<T>不存在不必要的编译错误T.

lll*_*lll 5

只需更改std::enable_if_t为非类型模板参数:

template<typename T, auto ID = 0>
class StrongAlias {
    T value;
public:
    template<typename... Args, std::enable_if_t<std::is_constructible_v<T, Args...>, int> = 0>
    StrongAlias(Args&&... args) noexcept(noexcept(T(std::declval<Args>()...)))
        : value(std::forward<Args>(args)...) {}
};
Run Code Online (Sandbox Code Playgroud)