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+...);
}
您可以将断言更改为
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
。
我看过 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+...);
}
您可以将断言更改为
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
。