我想定义一个通用的强别名类型,即一个类型
template<typename T, auto ID = 0>
class StrongAlias {
T value;
};
这样,对于
T
类型,可以使用与StrongAlias<T>
完全相同的方式来使用T
,但是StrongAlias<T, 0>
和StrongAlias<T, 1>
是不同的类型,无法有效地相互转换。为了尽可能完美地模仿
T
,我希望自己的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)...) {}
};
除了自
template parameter pack must be the last template parameter
以来不起作用,如clang 5.0会告诉我的那样。我想到的另一种使用SFINAE的方法是在返回类型中,但是由于构造函数没有返回类型,因此这似乎也不起作用。
有什么方法可以在构造函数中的可变参数模板参数包上使用SFINAE?
或者,如果没有,我可以用另一种方式完成我想要的吗?
请注意,就我而言,从
T
隐式构造是不够的,如StrongAlias<std::optional<int>>
的示例所示:如果只能从StrongAlias
隐式构造std::optional<int>
,则不能从std::nullopt
(std::nullopt_t
类型)构造它。将涉及2个用户定义的转化。我真的很想拥有别名类型的所有构造函数。编辑:
当然,如果不使用SFINAE从不兼容的参数构造
StrongAlias
,则可以实现该功能,并使程序无效。但是,尽管这在我的特定情况下是可以接受的行为,但是显然不是最佳的,因为StrongAlias
可以用于查询给定类型是否可以从某些参数构造的模板中(通过std::is_constructible
)。尽管这样会为std::false_type
生成T
,但会为std::true_type
生成StrongAlias<T>
,这可能意味着StrongAlias<T>
不会出现不必要的编译错误,而对于T
则不存在。 最佳答案
只需将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)...) {}
};