请考虑以下代码段:
template<typename T, class Tuple>
class vector
{
using size_type = typename Tuple::size_type;
template<typename... Elements,
typename = decltype(std::declval<Tuple>().reserve(size_type()))>
typename = decltype(std::declval<Tuple>().push_back(T())),
vector(Elements&&... elements)
{ /* ... */ }
};
我想定义一个嵌套的结构supports_reserve_push_back
,它是从std::true_type
派生的,只要上面的构造函数被启用(在另一种情况下派生自std::false_type
)。
我该怎么做?
答案 0 :(得分:2)
我修改了代码以使其成为build。并根据我的理解实施了您所要求的特质。
#include <iostream>
#include <type_traits>
#include <vector>
#include <map>
namespace example {
template<typename...>
using void_t = void;
template<typename T, class Tuple>
struct vector {
using size_type = typename Tuple::size_type;
using tuple_type = Tuple;
using elem_type = T;
template<typename... Elements>
vector(Elements&&... elements)
{ /* ... */ }
};
template <class T, typename = void>
struct supports_reserve_push_back : std::false_type {};
template <class Vec>
struct supports_reserve_push_back<Vec, void_t<
decltype(std::declval<typename Vec::tuple_type>().reserve(typename Vec::size_type())),
decltype(std::declval<typename Vec::tuple_type>().push_back(typename Vec::elem_type())) >
>
: std::true_type {};
}
int main() {
std::cout
<< example::supports_reserve_push_back<example::vector<int, std::vector<int>>>::value
<< '\n'
<< example::supports_reserve_push_back<example::vector<int, std::map<int, int>>>::value;
return 0;
}
有一点需要注意:
在负面情况下实例化类时,编写c'tor的方式最初会导致硬错误。这就是我从c'tor中删除chcck的原因。
我建议你首先定义类型特征,并使用它们来启用你的c'tors。
答案 1 :(得分:1)
#include <type_traits>
#include <utility>
template <typename...>
using void_t = void;
template <typename AlwaysVoid, template <typename...> class Operation, typename... Args>
struct detect_impl : std::false_type {};
template <template <typename...> class Operation, typename... Args>
struct detect_impl<void_t<Operation<Args...>>, Operation, Args...> : std::true_type {};
template <template <typename...> class Operation, typename... Args>
using detect = detect_impl<void_t<>, Operation, Args...>;
template <typename T, typename Sz>
using has_reserve = decltype(std::declval<T>().reserve(std::declval<Sz>()));
template <typename T, typename U>
using has_push_back = decltype(std::declval<T>().push_back(std::declval<U>()));
template <typename Tuple, typename T, typename size_type>
constexpr bool supports_reserve_push_back = detect<has_reserve, Tuple, size_type>{} && detect<has_push_back, Tuple, T>{};
测试:
template <typename T, class Tuple>
class vector
{
public:
using size_type = typename Tuple::size_type;
template <typename... Elements, typename U = Tuple,
std::enable_if_t<supports_reserve_push_back<U&, T, size_type>, int> = 0>
vector(Elements&&... elements)
{
}
template <typename... Elements, typename U = Tuple,
std::enable_if_t<!supports_reserve_push_back<U&, T, size_type>, int> = 0>
vector(Elements&&... elements)
{
}
};
答案 2 :(得分:1)
namespace details{
template<template<class...>class Z,class,class...Ts>
struct can_apply:std::false_type{};
template<template<class...>class Z,class...Ts>
struct can_apply<Z,std::void_t<Z<Ts...>,Ts...>:
std::true_type{};
}
template<template<class...>class Z,class... Ts>
using can_apply=details::can_apply<Z,void,Ts...>;
将你的decltypes包装成模板使用并做一些&&
并完成。
还有一个类似于上面的std实验。
template<class T, class U>
using push_back_r = decltype(std::declval<T>().push_back(std::declval<U>()));
template<class T>
using reserve_r = decltype(std::declval<T>().reserve(1));
template<class T, class U>
constexpr can_apply<push_back_r,T,U> has_push_back={};
template<class T>
constexpr can_apply<reserve_r,T> has_reserve={};
template<bool b>using bool_t=std::integral_constant<bool,b>;
template<class T,class U>
constexpr bool_t<has_push_back<T,U>&&has_reserve<T>>
efficiently_fillable_with = {};
然后efficiently_fillable_with<T,U>
是真实类型,如果您可以使用T保留空间然后将我们推入其中。保留T
和U
的r / l值类别:如果您想了解使用右值T
s填充U
的非同步左值:
efficiently_fillable_with<T&,U>
如果您想填写U const&
而不是rvalues,请传递U const&
。
答案 3 :(得分:0)
我会尝试以下方法:
让您的vector
模板类继承自超类,如下所示:
template<typename T, class Tuple> class vector
: public supports_reserve_push_back_impl<
vector_has_default_constructor<T, Tuple>::value() > {
// ...
}
现在,定义一个采用相同模板参数的vector_has_default_constructor
模板类:
template<typename T, class Tuple> class vector_has_default_constructor {
public:
// ...
};
在vector_has_default_constructor
:
使用与向量构造函数相同的完全签名定义constexpr bool value()
方法。此constexpr
方法返回true。
使用constexpr bool value()
签名定义重载...
,在重载决策中应该具有较低的优先级。此constexpr
返回false。
现在,这种情况被简化为定义两个简单的特化,supports_reserve_push_back_impl<true>
和supports_reserve_push_back_impl<false>
。
supports_reserve_push_back_impl<true>
包含您所需的supports_reserve_push_back
值,并由vector
继承。
supports_reserve_push_back_impl<false>
为空。