我最近一直在尝试 C++ 概念。我正在尝试以下范围扩展文档中的定义:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4569.pdf
的定义和用法Same让我感到困惑。由于我不知道的原因,作者没有给出明确的定义。所以我正在使用:
template <class T, class U>
concept bool Same()
{
return std::is_same<T, U>::value;
}
Run Code Online (Sandbox Code Playgroud)
问题是该文档给出了以下定义Assignable:
template <class T, class U>
concept bool Assignable()
{
return Common<T, U>() && requires(T&& a, U&& b) {
{ std::forward<T>(a) = std::forward<U>(b) } -> Same<T&>;
};
}
Run Code Online (Sandbox Code Playgroud)
它不起作用(在 GCC 6.3 下):一个简单的Assignable<int&, int&&>()概念检查给了我false(我已经验证该Common部分没问题)。我必须更改Same<T&>才能T&使其看起来有效。同样的Same<Type>检查也用在其他一些地方。
我的问题是:
Same正确吗?Same<T&>用 代替T&?有什么区别?谢谢你的帮助。
我对“原子约束”一章很好奇https://en.cppreference.com/w/cpp/language/constraints
它说
替换后 E 的类型必须恰好是 bool。不允许转换
和
f(0); // error: S<int>{} does not have type bool when checking #1,
// even though #2 is a better match
Run Code Online (Sandbox Code Playgroud)
哎哟。这意味着在使用 require 子句时没有 SFINAE 机制?这不是很糟糕吗?
因为我可以看到某些模板类型在遍历表达式后如何结果为 bool,但其他模板类型却看不到。现在我们又需要使用enable_if和东西了。痛得多?
有没有办法允许concept使用模板参数,可以使用提供的任何模板参数?
即模板参数占位符的某种通配符魔法?
\n一个使用示例:
\ntemplate<class Me, class TestAgainst>\nconcept derived_from_or_same_as = \n std::same_as<Me, TestAgainst> ||\n std::derived_from<Me, TestAgainst>;\nRun Code Online (Sandbox Code Playgroud)\n需要上面的内容是因为不幸的是,原始类型的 行为与和 的类类型不同。is_base_ofderived_from
现在我们可以定义一个Pair concept来检查提供的类型:
template<class P, class First, class Second>\nconcept Pair = requires(P p) {\n requires derived_from_or_same_as<decltype(p.first), First>;\n requires derived_from_or_same_as<decltype(p.second), Second>;\n};\nRun Code Online (Sandbox Code Playgroud)\n用例 [a] - 接受任何有效的As或As子类型对:
\n// this works well\nvoid doWithPairOfA(const Pair<A, A> auto& p) { /* */ }\nRun Code Online (Sandbox Code Playgroud)\n用例 …
以下代码是 -clause 的用法示例requires:
#include <type_traits>
template <typename T>
requires std::is_integral_v<T>
void take_integral(T value);
Run Code Online (Sandbox Code Playgroud)
它接受一个计算结果为bool值的表达式(std::is_integral_v<T>在本例中),并按预期工作。但是,当使用运算符对此类表达式求反时!,会导致编译错误:
#include <type_traits>
template <typename T>
requires !std::is_integral_v<T>
void take_integral(T value);
Run Code Online (Sandbox Code Playgroud)
来自 GCC 的诊断:
<source>:4:12: error: expression must be enclosed in parentheses
4 | requires !std::is_integral_v<T>
| ^~~~~~~~~~~~~~~~~~~~~~
| ( )
Compiler returned: 1
Run Code Online (Sandbox Code Playgroud)
来自 Clang 的诊断:
<source>:4:12: error: parentheses are required around this expression in a requires clause
requires !std::is_integral_v<T>
^~~~~~~~~~~~~~~~~~~~~~
( )
1 error generated.
Compiler returned: …Run Code Online (Sandbox Code Playgroud) 我尝试使用 gcc 10 构建以下内容-std=gnu++20 -fconcepts:
template <std::signed_integral T>\nclass MyClass{ T a; };\n\ntemplate <std::unsigned_integral T>\nclass MyClass{ T a; };\nRun Code Online (Sandbox Code Playgroud)\n\n为什么这段代码会导致以下错误?
\n\n> declaration of template parameter \xe2\x80\x98class T\xe2\x80\x99 with different constraints\n> 55 | template <std::unsigned_integral T>\n> | ^~~\nRun Code Online (Sandbox Code Playgroud)\n\n应该没问题吧?
\ntemplate-specialization class-template c++-concepts c++20 gcc10
我们如何将这个问题中的需求转换为一个概念
我已尝试以下操作:
template< typename U, typename Tin, typename Tout>
concept MyConditions =
(
U::value_type
&& Tin::value_type
&& Tout::value_type
&& std::is_floating_point_v<typename Tin::value_type>
&& std::is_integral_v<typename U::value_type>
&& std::is_floating_point_v<typename Tout::value_type>
);
Run Code Online (Sandbox Code Playgroud)
这个概念现在应用于我的成员函数之一:
class test_concept
{
template< typename U, typename Tin, typename Tout>
requires MyConditions <U, Tin, Tout>
static void test_routine(const U&, const Tin&, Tout& );
}
Run Code Online (Sandbox Code Playgroud)
测试时:
std::vector<double> test{ };
std::vector<int> testi{ };
std::vector<double> test2{ };
test_concept::test_routine(testi, test, test2);
Run Code Online (Sandbox Code Playgroud)
使用clang我收到错误消息,指出未找到匹配项,并附有一条注释:
注意:因为替换的约束表达式格式不正确:依赖类型名称 'vector<int, allocator >::value_type' U::value_type 之前缺少 'typename'
在下面的代码中,为什么第二个和第三个概念会产生编译错误?
#include <tuple>
template <class P>
concept IsPair1 = std::tuple_size<P>::value == 2;
template <class P>
concept IsPair2 = std::tuple_size_v<P> == 2;
template <class P>
concept IsPair3 = requires { typename std::tuple_size<P>; } && std::tuple_size_v<P> == 2;
constexpr bool intIsPair1 = IsPair1<int>; // OK, false
constexpr bool intIsPair2 = IsPair2<int>; // error: incomplete type 'std::tuple_size<int>' used in nested name specifier
constexpr bool intIsPair3 = IsPair3<int>; // error: incomplete type 'std::tuple_size<int>' used in nested name specifier
Run Code Online (Sandbox Code Playgroud)
/usr/local/Cellar/gcc/11.1.0_1/include/c++/11.1.0/tuple:1334:61: error: incomplete type 'std::tuple_size<int>' used …Run Code Online (Sandbox Code Playgroud) 有一个std::convertible_to<T>概念是检查调用结果是否可以转换为某种类型。
但我想检查函数是否具有确切的返回类型。我怎样才能做到这一点?
我是模板和概念的高级使用新手,所以这里有一个有点复杂的问题:
我Traits对每个Source类别的许多特征都有一些概念:
template<typename _Traits>
concept Traits = requires
{
std::same_as<std::decay_t<decltype(_Traits::token)>, std::string_view>;
};
Run Code Online (Sandbox Code Playgroud)
我有一些模板类使用这个概念来处理object_one各种特征(例如,一半的Source类返回object_one):
template <concepts::Traits _Traits>
class Object_one_handler final
{
static std::string handle_object(const object_one& obj) {/*...*/}
};
Run Code Online (Sandbox Code Playgroud)
然后我有了来自不同集合的Objects_handlers各种对象的处理程序的概念:{object_one, object_two, object_three}SourcesTraits
template<template <concepts::Traits _Traits> class _Objects_handlers, typename _Object>
concept Objects_handlers = requires(const _Object& obj)
{
// has handle_object method
{ _Objects_handlers<???????>::handle_object(obj) } -> std::same_as<std::string>;
};
Run Code Online (Sandbox Code Playgroud)
最后,我创建了一些database指定为模板参数的内容Object_handler:
template<concepts::Objects_handlers _handler>
class database
{...};
Run Code Online (Sandbox Code Playgroud)
(实际上所有概念都有额外的要求,但这里并不重要) …
比方说,我有我的List<T>课。我有很多函数,我必须传递我T类型的单个对象。例如
void add(const T& item)
{
...
}
Run Code Online (Sandbox Code Playgroud)
T如果是某个类或结构就有意义。但是,如果T是字节或整数,则通过引用传递它是没有意义的,甚至是错误的,因为内存指针花费 8 个字节(在 32 位系统上为 4 个字节),即我通过 8 字节大小的指针传递 1 字节大小的数据类型。
所以我决定使用using指令定义参数数据类型。有点儿:
using argType = const T&; requires sizeof(T) > 8
using argType = T; requires sizeof(T) <= 8
Run Code Online (Sandbox Code Playgroud)
但是,显然,这段代码不起作用。您能为我提出其他解决方案吗?
c++-concepts ×10
c++ ×9
c++20 ×9
templates ×4
auto ×1
function ×1
gcc10 ×1
optimization ×1
return-type ×1