我在尝试弄清楚如何指定转发引用(以前由 Scott Meyers 称为通用引用)的默认参数时遇到困难。
这是尝试做我想做的事情的代码示例:
struct encoder_t {
} const encoder = {};
struct validator_t {
} const validator = {};
struct test {
template <typename Range, typename Encoding, typename Validation>
test ( Range&& range, Encoding&& encoding = encoder, Validation&& validation = validator ) {
}
};
int main() {
test( "woof" );
}
Run Code Online (Sandbox Code Playgroud)
仔细检查这些错误,您发现可以通过默认模板参数来使其工作,然后默认构造参数:
// Works! But the syntax is strange... potential ramifications/deduction mishaps?
// Is this the "proper" way to default these …Run Code Online (Sandbox Code Playgroud) c++ templates constructor default-arguments forwarding-reference
我正在阅读有关类模板的模板参数推导的论文http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0091r3.html。这个功能是 C++17 标准中的,有些事情让我感到困惑。
template <typename T>
class Something {
public:
// delete the copy and move constructors for simplicity
Something(const Something&) = delete;
Something(Something&&) = delete;
explicit Something(T&&) { ... }
explicit Something(const T&) { ... }
template <typename U, typename EnableIfNotT<U, T>* = nullptr>
Something(U&&) { ... }
};
Run Code Online (Sandbox Code Playgroud)
鉴于上面的代码,如果有人尝试像这样实例化上述模板的实例
auto something = Something{std::shared_ptr<int>{}};
Run Code Online (Sandbox Code Playgroud)
右值引用重载总是会被调用吗?由于考虑扣除的过载集是
template <typename T>
Something<T> F(T&&) { ... }
template <typename T>
Something<T> F(const T&) { ... }
template <typename T, typename U, …Run Code Online (Sandbox Code Playgroud) 我正在阅读这个 stackoverflow 答案const T&&,其中给出了不是通用(转发)参考的一个原因:
允许 const T&& 充当转发引用,将无法重载仅采用右值引用作为参数的模板函数。
我不知道这是什么意思。我想这意味着同一个函数(模板)有两个重载,其中一个重载作为参数const T&&。我还假设这些重载之一将始终被调用,而另一个永远不会被调用。
如果我的假设是正确的,那么这两个重载函数是什么?或者如果我错了,引用的段落实际上是什么意思?
谢谢。
我有一个理想情况下应如下所示的函数:
\ntemplate<typename... t_buffers, t_function function>\nvoid iterate_buffers(t_buffers &&... buffers, t_function &&function);\nRun Code Online (Sandbox Code Playgroud)\n但是,除非参数包类型位于最后,否则无法推断出参数包类型,因此我的函数签名如下:
\ntemplate<typename... t_buffers_and_function>\nvoid iterate_bufferes(t_buffers_and_function &&... buffers_and_function);\nRun Code Online (Sandbox Code Playgroud)\n然后参数会被重新排列,以便函数排在第一位。为了执行此改组,我使用了此处描述的技术,但在尝试转发元组时遇到了问题。
\n这是一个存在问题的简化示例:
\ntemplate<typename... t_args>\nvoid inner(std::tuple<t_args &&...> args) {};\n\ntemplate<typename... t_args>\nvoid outer(t_args &&... args) {\n inner(std::forward_as_tuple(std::forward<t_args>(args)...));\n}\nRun Code Online (Sandbox Code Playgroud)\n如果我传递右值(例如通过调用outer(1, 2);),它会按预期工作。但是,如果我传递左值 ( int x = 1; int y = 2; outer(x, y);),则会出现以下语法错误:
error: could not convert \xe2\x80\x98std::forward_as_tuple(_Elements&& ...) [with _Elements = {int&, int&}]((* & std::forward<int&>((* & args#1))))\xe2\x80\x99 from \xe2\x80\x98std::tuple<int&, int&>\xe2\x80\x99 to \xe2\x80\x98std::tuple<int&&, int&&>\xe2\x80\x99\ninner(std::forward_as_tuple(std::forward<t_args>(args)...));\n~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nRun Code Online (Sandbox Code Playgroud)\n因此forward_as_tuple …
c++ tuples variadic-templates perfect-forwarding forwarding-reference
我正在使用的静态分析工具提示我需要std::forward调用链中以下函数的参数:
template<typename T, std::size_t size>
constexpr void f(T (&& arr)[size]) { /* linter: use std::forward on 'arr' here */ }
Run Code Online (Sandbox Code Playgroud)
因为它将函数参数类型标识为转发引用。
然而,对多个编译器的简单测试表明,这不是转发引用。下面的例子
void g() {
int a[3]{1, 2, 3};
f(a); // #1
}
Run Code Online (Sandbox Code Playgroud)
#1在(DEMO )处被拒绝,明确指出函数参数是右值引用:
Run Code Online (Sandbox Code Playgroud)error: cannot bind rvalue reference of type 'int (&&)[3]' to lvalue of type 'int [3]'
T&&的模板化数组函数&&参数f不是转发引用?在函数中我需要区分左值和右值引用,所以明显的路径是重载:
void myfunc(A&& a);
void myfunc(const A& a);
Run Code Online (Sandbox Code Playgroud)
这具有完全所需的行为,具有良好定义的类型和隐式转换.然而,代码重复太多,我宁愿将相关决策封装在内部,只保留一个函数,因此通过通用引用可能是一个选项:
template <typename A> void myfunc(A&& a);
Run Code Online (Sandbox Code Playgroud)
然而,这有一个令人遗憾的缺点,即现在任何对象都可以作为第一个参数传递,因此可以通过enable_if强加约束:
template <typename T, class = typename enable_if<
is_same<typename remove_const<typename remove_reference<T>::type>::type, A>::value,
T>::type>
void myfunc( T&& a);
Run Code Online (Sandbox Code Playgroud)
这几乎似乎可以完成这项工作,但是(我想已经通过模板化)我们已经失去了一个很好的重载属性,可以触发隐式转换构造函数到类型A(比如来自类型C参数).重载不是一个选项,因为某些函数可能有3个或更多A &&参数,无意处理组合爆炸.隐式转换可以以某种方式恢复吗?当然,一种解决方法可能是例如为A添加其他允许的参数类型,并在main函数中执行任何所需的转换,但这是侵入性的,丑陋的,明确的含义并产生混淆(原始C参数可能是左值[reference]并通过转换产生右值).有更好的方法吗?
我有一个关于转发引用的具体问题。(我认为)我理解 r 值引用和std::move,但我无法理解转发引用:
#include <iostream>
#include <utility>
template <typename T> class TD; // from "Effective Modern C++"
void consume(const int &i) { std::cout << "lvalue\n"; }
void consume(int &&i) { std::cout << "rvalue\n"; }
template <typename T>
void foo(T&& x) {
// TD<decltype(x)> xType; - prints int&&
consume(x);
}
int main() {
foo(1 + 2);
}
Run Code Online (Sandbox Code Playgroud)
T是int,没关系。如果x是 type int&&,为什么它打印“lvalue”而我们需要std::forward?我的意思是,从哪里转换int&&到const int&这里?
当我想要使用函数参数复制语义const T&或使用函数参数移动语义时,如何处理通用引用T&&。后者隐藏了第一个。
下面是带有代数向量运算符的示例代码。
#include <array>
#include <iostream>
template<typename T>
void neg(T &a) { for (auto &i : a) i = -i; }
// object 'a' remains available
template<typename T>
auto operator-(const T &a) { std::cout << "1\r\n"; T b = a; neg(b); return b; }
// object 'a' terminates its life
template<typename T>
auto operator-(T &&a) { std::cout << "2\r\n"; neg(a); return std::move(a); }
// make an rvalue
template<typename T1, typename T2>
auto operator+(const T1 &a, …Run Code Online (Sandbox Code Playgroud) 这是我使用 C++20 进行柯里化的实现:
#include <concepts>
#include <functional>
constexpr auto
curry(std::invocable auto f)
{
return f();
}
constexpr auto
curry(auto f)
{
return [=](auto x) { return curry(std::bind_front(f, x)); };
}
constexpr int
f(int a, int b, int c)
{
return a * b * c;
}
constexpr auto
g(auto... args)
{
return (1 * ... * args);
}
constexpr int
h()
{
return 42;
}
int
main()
{
static_assert(curry(f)(2)(3)(7) == 42);
static_assert(curry(g<int, int, int, int>)(1)(2)(3)(7) == 42);
static_assert(curry(h) == 42); …Run Code Online (Sandbox Code Playgroud) MSVC /std:c++20 报告约束自动&& 的错误如下所示
#include<concepts>
class Base { public: Base() {} };
class Derived : public Base { public: Derived() {} };
template<typename T> concept con = std::is_class_v<T>
&& std::derived_from<T, Base>;
void f(con auto&& x) {}
int main()
{
f(Derived()); // r value: Ok
Derived d;
f(d); // l-value: no matching overloaded function found
}
Run Code Online (Sandbox Code Playgroud)
从“con auto&&”中删除“con”,上面的代码编译没有错误。我想了解为什么向 auto&& 模板参数添加约束会将其从“通用引用”更改为仅 R 值引用。此行为符合 C++20 标准还是 MSVC 独有的行为?
在互联网上搜索 C++ 论坛,没有找到任何解释这种特定语言用例的内容。然而,可能有一些我错过或没有注意到的事情。
c++ ×10
templates ×3
c++11 ×2
c++20 ×2
c++17 ×1
constructor ×1
currying ×1
forwarding ×1
tuples ×1