如何编写通用特征以将T :: value_type与其他特征进行匹配?

时间:2018-11-15 13:35:54

标签: c++ c++17

我正在尝试创建一种“包装器特征”,它可以针对某些T和某些现有的一元特征Concept检测到:

  • T是“可迭代的”,并且
  • T::value_type满足Concept

这很有用,因为我还有其他可能期望各种类型的代码,包括std::vector<various types>,并且我想使用该包装器特征来enable_if所述代码中的各种功能。

这是草图:

#include <type_traits>
#include <vector>

template <typename T, typename = void>
struct is_iterable : std::false_type {};

template <typename T>
struct is_iterable<T, std::void_t<decltype(std::declval<T&>().begin() == std::declval<T&>().end())>> : std::true_type {};

template <class T>
constexpr bool is_iterable_v = is_iterable<T>::value;


template <typename T, typename = void>
struct iterable_value_type
{
    using type = std::false_type;
};

template <typename T>
struct iterable_value_type<T, std::void_t<decltype(T::value_type)>>
{
    using type = typename T::value_type;
};

template <class T>
using iterable_value_type_t = typename iterable_value_type<T>::type;


// Transforms a concept "does type T have property P" into the concept
// "is type T1 an iterable with value_type T2 where T2 has property P"
template <typename T, template <typename...> typename BaseConcept>
struct CollectionConcept
{
    static constexpr bool value = is_iterable_v<T> && BaseConcept<iterable_value_type_t<T>>::value;
};

int main()
{
    static_assert(std::is_arithmetic<int>::value);
    static_assert(CollectionConcept<std::vector<int>, std::is_arithmetic>::value);
}

不幸的是第二个static_assert触发器,我不知道为什么。

我该如何实现?

1 个答案:

答案 0 :(得分:7)

罪魁祸首是这个:

template <typename T>
struct iterable_value_type<T, std::void_t<decltype(T::value_type)>>
{
    using type = typename T::value_type;
};

您正在将decltype应用于类型,而不是表达式。

要修复特征,请删除decltype(由于名称依赖性,请加上typename作为前缀):

template <typename T>
struct iterable_value_type<T, std::void_t<typename T::value_type>>
{
    using type = typename T::value_type;
};

[Live example]