我想定义一个通用的强别名类型,即一个类型
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)...) {}
};
关于c++ - 可变参数构造函数中的 SFINAE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49372964/