我想把对象放入一个容器中(哪个容器不固定)。
为此我想使用这个概念std::output_iterator。
我如何定义一个以 astd::insert_iterator<std::vector<T>>和 a为例的函数std::insert_iterator<std::list<T>>?
这个概念std::output_iterator需要两个模板参数:I和T。所以我不确定如何声明这样的函数。
我可以像老派那样做<algorithm>并声明如下:
template<typename OutIter>
void foo(OutIter writer);
Run Code Online (Sandbox Code Playgroud)
但在我看来,这并不是那么有表现力。
更新:这是我基于@RemyLebeau 的回答的尝试:
#include <iterator>
#include <vector>
template<typename I, typename T, std::output_iterator<I,T> OutIter>
void foo(OutIter writer) {
writer++ = T();
}
int main() {
std::vector<int> ints;
auto inserter = std::insert_iterator(ints,ints.end());
foo(inserter);
}
Run Code Online (Sandbox Code Playgroud)
我希望能够做到:
\ntemplate<typename T> // line 8\nclass Base;\n\ntemplate<typename T>\nconcept C = std::is_base_of_v<Base<T>,T>;\n\ntemplate<C T> // line 17\nclass Base {\n // ...\n};\n\n// ...\n\nclass MyClass : public Base<MyClass> {\n // ...\n};\nRun Code Online (Sandbox Code Playgroud)\n也就是说,有一个模板类Base,它将派生自它的类(CRTP )作为其模板参数。我想要一个概念来约束源自的C模板T类型。BaseTBase<T>
但是,这不会编译,因为:
\nx.cpp:17:10: error: type constraint differs in template redeclaration\ntemplate<C T>\n ^\nRun Code Online (Sandbox Code Playgroud)\n我必须Base在第 8 行使用\xe2\x80\x94C来向前声明typename,但我还没有声明C,你不能向前声明概念。
那么我怎样才能得到我想要的东西呢?
\n考虑以下概念:
template< typename T, std::size_t Value >
concept Is_ = requires(T&&)
{
requires Value == std::remove_cvref_t< T >::value;
};
Run Code Online (Sandbox Code Playgroud)
与函数重载相关:
template< Is_< 2 > T >
void foo(T&&)
{
std::cout << "Value is 2!" << std::endl;
}
template< typename T >
void foo(T&&)
{
std::cout << "Either no value or it isn't 2!" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
最后,我们来玩一下上面的函数:
foo(std::integral_constant< std::size_t, 2 >{}); // Choose the constrained overload
foo(std::tuple{}) // Choose the generic impl
Run Code Online (Sandbox Code Playgroud)
现在,如果我定义以下辅助变量模板:
template< typename T >
inline constexpr auto …Run Code Online (Sandbox Code Playgroud) 我对容器类型有一个相对简单的概念定义,它接受特定的值类型:
template <typename T>
concept FooContainer = requires(T cont){
std::begin(cont);
std::end(cont);
requires std::is_same_v<typename T::value_type, Foo>;
};
Run Code Online (Sandbox Code Playgroud)
我想定义一个可以接受两个参数的函数,每个参数都是满足这个概念的任何容器类型。到目前为止我已经
void func(const FooContainer auto& cont1, const FooContainer auto& cont2){
// ...
}
Run Code Online (Sandbox Code Playgroud)
这工作正常,我可以将任何我想要的左值或右值传递到 cont1 或 cont2 中,因为我认为 C++ 自动将 a 绑定const lvalue reference到rvalue参数。不过,我想知道这里如何利用完美转发,以便将值类别自动转发到函数中。
我知道转发引用只能在模板化函数中使用,但这让我有点困惑,因为参数已经是模板化概念......
我尝试在不同的地方添加:即在概念&&模板中添加,但不确定它到底有什么作用。typename T
我正在寻找一种方法来定义一个变量,该变量的类型取决于我的类模板化的类型的成员的类型,但需要注意的是该成员变量可能不存在。由于我仅在成员确实存在时访问块中的变量constexpr,因此我不关心声明它或它是什么类型。但是,我了解到这typename conditional<hasMember<T>, decltype(T::member), int>不起作用,因为未使用的分支仍然需要编译。
这是我希望开始工作的一个例子:
#include <iostream>
using namespace std;
struct X{};
struct Y{string member;};
template<class T>
concept hasMember = requires (T t) {t.member;};
template<class T>
struct A{
void hi(T a) {
// stuff
typename conditional<hasMember<T>, decltype(T::member), int /*member is unused if hasMember<T> is false, so I don't care what type it is or if it exists*/>::type member;
if constexpr (hasMember<T>){
member = a.member;
}
// stuff
if constexpr (hasMember<T>){
std::cout << member<< std::endl;
}
}; …Run Code Online (Sandbox Code Playgroud) 这是我尝试过的用于测试c ++概念功能的代码.但是,即使在g ++ 6.2.0版本上使用标志-fconcepts后它似乎也无法工作.任何帮助它运作的帮助都会很棒!
#include <iostream>
using namespace std;
#include <list>
#include <vector>
#include <algorithm>
#include <iterator>
#include <bits/stdc++.h>
using namespace std::literals;
template<typename ptr_t >
requires RandomAccessIterator<ptr_t>
void mysort(ptr_t first, ptr_t last)
{
sort(first, last);
}
int main()
{
vector<int> v{22, 11, 55, 33, 44};
list<int> l{22, 11, 55, 33, 44};
mysort(begin(v), end(v));
mysort(begin(l), end(l));
}
Run Code Online (Sandbox Code Playgroud)
这是我编译它的方式:
g++-6 concepts.cpp -fconcepts
Run Code Online (Sandbox Code Playgroud)
这是我得到的错误:
error: ‘RandomAccessIterator’ was not declared in this scope
Run Code Online (Sandbox Code Playgroud)
我将拼写更改为random_access_iterator但仍然无效.
6.2.13节中的文档C++ Working Draft定义了RandomAccessIterator的存在.
我尝试使用约束进行类专门化:
struct A {};
struct B {};
struct C {};
template<typename T>
concept bool AorB() {
return std::is_same<T, A>::value || std::is_same<T, B>::value;
}
template<typename T>
class X {};
template<AorB T>
class X {};
int main() {
X<A> x1; // error: redeclaration 'template<class T> class X' with different constraints class X {};
X<B> x2;
X<C> x3;
}
Run Code Online (Sandbox Code Playgroud)
我不知道我在这里犯了错误,或者这一般是不可能的?
有什么可以替代这种方法?我可以使用CRTP到一个公共基本模板的专业化,但这对我来说看起来很难看.
我只是在阅读 C++20 概念的例子。现在我正在尝试创建一个函数,该函数将打印出给定类型是否是哈希表或不使用与部分专业化混合的概念。但不幸的是它不起作用。
#include <iostream>
#include <string>
template<typename T>
concept Hashtable = requires(T a) {
{ std::hash<T>{}(a) } -> std::size_t;
};
struct Foo {};
template <typename T>
void Bar() {
std::cout << "Type T is not a hashtable" << std::endl;
}
template <Hashtable T>
void Bar<T> {
std::cout << "Type T is a hashtable" << std::endl;
}
int main()
{
Bar<Foo>();
Bar<std::string>();
}
Run Code Online (Sandbox Code Playgroud)
我正在使用编译器版本 GCC HEAD 9.0.1,编译器标志是g++ prog.cc -Wall -Wextra -I/opt/wandbox/boost-1.69.0/gcc-head/include -std=gnu++2a "-fconcepts". 它给了我以下编译器错误:
prog.cc:18:6: error: template-id 'Bar<T>' …Run Code Online (Sandbox Code Playgroud) 我可能对std :: overloaded提案和/或概念有些困惑,但是根据目前对这两者的理解,我有以下问题:
为什么C ++ 20不只是概念化/如果对std :: visit进行constexprify,所以它知道基于传递给它的参数类型该怎么做。
例如为什么我们不能有std :: visit根据传递的参数的概念来修改它的行为(它所需要的只是函数在前,变量在后)。
因此,例如,这两个visit参数都接受3个参数,但逻辑不同。
std::variant<int, double> v1=4.7;
std::variant<bool, std::string> v2=false;
// calls lambda that is a better fit(double one)
std::visit([](int& a){std::cout<< sizeof (a);},[](double& a){std::cout << a;} , v1);
// calls lambda on variant v1 and then variant v2
std::visit([](auto& a){}, v1, v2);
Run Code Online (Sandbox Code Playgroud) 我刚刚从 Saar Raz 的演示视频中了解到以下限制:
template <typename T>
concept C = sizeof(T) > 1;
template <typename T>
concept D = sizeof(T) > 1 && sizeof(T) >= 4;
Run Code Online (Sandbox Code Playgroud)
对重载不明确,因为分别sizeof(T) > 1出现在C和的原子约束D不等价。
他们不是因为标准说[templ.constr]:
两个原子约束是相同的,如果它们是由相同的形成表达[...]
关键是表达式是斜体,指的是语法术语,定义为[expr.comma]:
表达:
赋值表达式
表达式,赋值表达式
我不明白为什么原子约束需要涉及赋值。为什么会这样?
我必须承认,上面的代码最好通过概念细化来编写,但我直觉地认为这种编写方式也是正确的。
c++ ×10
c++-concepts ×10
c++20 ×7
templates ×2
c++17 ×1
crtp ×1
decltype ×1
stl ×1
type-traits ×1
variant ×1