C++17中概念的实现

Implementation of concepts in C++17

我看过 Bjarne stroustrup 的名为 "Concepts the future of generic programming" 的演讲,我想也许我可以用 C++17 编写 "Concepts"... 但我是一名 C 程序员,大约 6 个月前我开始使用 C++……所以我不知道为什么,但我在使用这段代码时遇到了麻烦。有人可以帮助我吗?

我用一个简短的 tmp 代码实现了 Addable 的概念... 这个想法是在 C++20 中将是这样的:

  template<typename T>
  concept Summable = requires(T x) { x + x; };

  template<typename T> requires Summable<T>
  T sum(T n1, T n2) {
     return n1 + n2;
  }

而这段代码是 C++17 中实际拥有的代码:

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

 template <typename T, typename U>
 struct Addable < T, U,
                 std::void_t<decltype(std::declval<T&>()+std::declval<U&>())> > 
             : std::true_type {};

top 的代码可以编译并运行,但是当我编写以下代码时无法编译...

 template<typename Head, typename ... Tail>
 auto sum(Head h, Tail ... args) {
    static_assert(Addable<Head, Tail...>::value, "Requires addable objects");
    return h+(args+...);
 }

您的代码 does work 只要您只向 sum 提供两个参数即可。

问题是,当您调用类似 sum(1, 2, 3) 的内容时,Addable<Head, Tail...> 变为 Addable<int, int, int>,这与您的 Addable<T, U, void> 部分专业化不匹配。如果您使用超过三个参数调用 sum,则根本没有匹配的 Addable 模板,因为 Addable 只接受三个模板参数。

如果您希望能够处理两个以上的参数,则需要采用不同的方法。这就是我想出的。它使用与您使用的方法类似的方法,只是使用额外的层间接来支持两个以上的参数:

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

template <typename T, typename U>
struct Helper<T, U, std::void_t<decltype(std::declval<T>() + std::declval<U>())>> : std::true_type {};

template <typename, typename...>
struct Addable : std::false_type {};

template <typename T, typename U, typename... V>
struct Addable<T, U, V...> : std::conditional_t<Addable<T, U>::value,
                                                Addable<U, V...>,
                                                std::false_type> {};

template <typename T, typename U>
struct Addable<T, U> : Helper<T, U> {};

template<typename Head, typename ... Tail>
auto sum(Head h, Tail ... args) {
    static_assert(Addable<Head, Tail...>::value, "Requires addable objects");
    return h+(args+...);
}

Live Demo

您可以将断言更改为

template <typename Head, typename ... Tail>
auto sum(Head h, Tail ... args) {
    static_assert((Addable<Head, Tail>::value || ...), "Requires addable objects");
    return (h + ... + args);
}

因为你的特质只适用于两种类型。

请注意,SFINAE 看起来更像 概念 而不是 static_assert