我有一个带有模板参数foo
的类Tuple
,我想提供一个可变参数构造函数来初始化类型m_elements
的成员变量Tuple
,每当表达式m_elements{ static_cast<typename Tuple::value_type>(std::forward<Elements>(elements))... }
已定义。
我们可以通过以下方式执行此操作:
template<class Tuple>
struct foo
{
using value_type = typename Tuple::value_type;
template<class... Elements, class U = Tuple,
class = decltype(U{ static_cast<value_type>(std::declval<Elements>())... })>
foo(Elements&&... elements)
: m_elements{ static_cast<value_type>(std::forward<Elements>(elements))... }
{}
Tuple m_elements;
};
现在,是否启用此构造函数还应该依赖于其他一些条件。所以,我需要写一些像
这样的东西template<class... Elements, class U = Tuple,
class = std::enable_if_t</* some other conditions depending on U */>,
class = decltype(U{ static_cast<value_type>(std::declval<Elements>())... })>
我想根据std::is_constructible
检查我的第一个条件,以便我可以将此检查移至enable_if
。这可能吗?我已尝试使用std::is_constructible_v<U, decltype(static_cast<value_type>(std::declval<Elements>()))...>
,但这似乎与以前的检查不同。
例如,foo<bar<3>>{1, 2, 3};
与
template<std::size_t N>
struct bar
{
using value_type = double;
double data[N];
};
将使用上一次检查进行编译,但会产生新错误。
答案 0 :(得分:1)
如上所述Rostislav,如果T
不是函数类型,std::is_constructible_v<T, Args>
是true
iff变量定义T obj(std::declval<Args>()...);
格式正确。 bar<1> obj(0.);
中的情况并非如此,因为bar<1>
没有相应的构造函数。
相比之下,bar1<1> obj{ 0. };
格式正确。使用建议的Detection Toolkit,我们可以使用
template<class T, typename... Arguments>
using initializable_t = decltype(T{ std::declval<Arguments>()... });
template<class T, typename... Arguments>
constexpr bool is_initializable_v = is_detected_v<initializable_t, T, Arguments...>;
并将支票更改为
template<class... Elements, class U = Tuple,
class = std::enable_if_t<is_initializable_v<U, decltype(static_cast<value_type>(std::declval<Elements>()))...>>>
我认为这比简单的decltype
方法更具可读性。
答案 1 :(得分:0)
is_constructible
特征表现不同的原因是确实没有bar
的构造函数将三个int
值作为参数。在这种特定情况下,使用聚合初始化。
但是你可以通过使用一个简单的帮助enable_if
将测试放入struct
:
#include <type_traits>
template<typename T>
struct test : std::true_type
{
};
template<class Tuple>
struct foo
{
using value_type = typename Tuple::value_type;
template<class... Elements, class U = Tuple,
class = std::enable_if_t<
test<decltype(U{ static_cast<value_type>(std::declval<Elements>())... })>::value>
/* && your other tests */
>
foo(Elements&&... elements)
: m_elements{ static_cast<value_type>(std::forward<Elements>(elements))... }
{}
Tuple m_elements;
};
template<std::size_t N>
struct bar
{
using value_type = double;
double data[N];
};
int main()
{
foo<bar<3>>{1, 2, 3};
}
或者,您可以使用this问题的任何答案创建类型特征,将decltype
魔法推送到单独的位置。