我正在尝试编写一个函数,该函数以一个形式返回一个可变参数包的子集std::tuple.理想情况下,该函数不应具有运行时开销(没有不必要的副本),并且应该允许用户访问lvalue引用并修改它们.
应保持值类型,lvalue引用和const lvalue引用.Temporaries(rvalue引用)应该"转换"为值类型,以避免创建无效引用(对临时引用的引用).
期望结果的示例:
int lr = 5;
const int& clr = lr;
auto t = make_subpack_tuple(lr, clr, 5);
static_assert(is_same
<
decltype(t),
std::tuple<int&, const int&, int>
>{}, "");
// Ok, modifies lr:
std::get<0>(t) = 10;
// Compile-time error, intended:
// std::get<1>(t) = 20;
// Ok, 5 was moved into the tuple:
std::get<2>(t) = 30;
Run Code Online (Sandbox Code Playgroud)
示例不完整实施:
template<typename... Ts>
auto make_subpack_tuple(Ts&&... xs)
{
return std::tuple
<
some_type_trait<decltype(xs)>...
>
(
std::forward<decltype(xs)>(xs)...
);
} …Run Code Online (Sandbox Code Playgroud) 我创建了一个简单的类型特征来删除右值引用:
template <typename T>
struct remove_rvalue_reference { using type = T; };
template <typename T>
struct remove_rvalue_reference<T&&> { using type = T; };
template <typename T>
using remove_rvalue_reference_t =
typename remove_rvalue_reference<T>::type;
Run Code Online (Sandbox Code Playgroud)
我用它来实现一个copy_if_rvalue(x)函数,其返回类型取决于传递的参数:
template <typename T>
constexpr auto copy_if_rvalue(T && x)
-> remove_rvalue_reference_t<decltype(std::forward<decltype(x)>(x))>
{
return std::forward<decltype(x)>(x);
}
Run Code Online (Sandbox Code Playgroud)
为了确保函数返回正确的类型,我编写了一些简单的静态断言:
// literal
static_assert(std::is_same<
decltype(copy_if_rvalue(0)), int
>{});
// lvalue
int lv = 10;
static_assert(std::is_same<
decltype(copy_if_rvalue(lv)), int&
>{});
// const lvalue
const int clv = 10;
static_assert(std::is_same<
decltype(copy_if_rvalue(clv)), const int& …Run Code Online (Sandbox Code Playgroud) 我在我的一个真实项目中遇到了一个难以调试的情况,我不小心访问了已被移动的lambda中的局部变量的引用.访问是从另一个线程完成的,但移动的lambda保持活着直到第二个线程完成.
该错误仅在禁用优化时发生,并且是由粗心重构引起的.
我创建了一个最小的例子(可在wandbox上找到),它可以重现这个问题:
struct state
{
int x = 100;
};
template <typename TF>
void eat1(TF&& f)
{
// Call the lambda.
f();
// Simulate waiting for the second thread
// to finish.
std::this_thread::sleep_for(1000ms);
}
template <typename TF>
void eat0(TF&& f)
{
// Move the lambda to some other handler.
eat1(std::forward<TF>(f));
}
void use_state(state& s)
{
// Will print `100`.
std::cout << s.x << "\n";
// Separate thread. Note that `s` is captured by
// reference. …Run Code Online (Sandbox Code Playgroud) 我试图boost::variant使用不完整的包装类和std::vector我的间接技术来定义和访问"递归" .我的实现适用于libstdc ++,但不适用于libc ++.
这是我定义我的变体的方式:
struct my_variant_wrapper;
using my_variant_array = std::vector<my_variant_wrapper>; // <- indirection here
using my_variant = boost::variant<int, my_variant_array>;
struct my_variant_wrapper
{
my_variant _v;
template <typename... Ts>
my_variant_wrapper(Ts&&... xs) : _v(std::forward<Ts>(xs)...) { }
};
Run Code Online (Sandbox Code Playgroud)
我std::vector用来引入间接(因此动态分配将阻止my_variant具有无限大小).
由于纸张N4510 ("标准容器的最小不完全类型支持")std::vector<my_variant_wrapper>,我非常有信心我可以使用,哪里my_variant_wrapper是不完整的类型:
根据WG21的2015年页面,该论文获得批准.
根据此页面,libstdc ++始终支持这些功能.
根据这个页面,它在libc ++ 3.6中实现.
我随后访问该变体如下:
struct …Run Code Online (Sandbox Code Playgroud) 考虑以下代码段:
template <typename TF>
void post(TF){ }
template <typename... TFs>
struct funcs : TFs...
{
funcs(TFs... fs) : TFs{fs}... { }
void call()
{
(post([&]{ static_cast<TFs&>(*this)(); }), ...);
}
};
Run Code Online (Sandbox Code Playgroud)
g ++ 7.0无法编译,出现以下错误:
prog.cc: In lambda function:
prog.cc:10:43: error: parameter packs not expanded with '...':
(post([&]{ static_cast<TFs&>(*this)(); }), ...);
~~~~~~~~~~~~~~~~~~~~~~~~^~
prog.cc:10:43: note: 'TFs'
prog.cc: In member function 'void funcs<TFs>::call()':
prog.cc:10:13: error: operand of fold expression has no unexpanded parameter packs
(post([&]{ static_cast<TFs&>(*this)(); }), …Run Code Online (Sandbox Code Playgroud) 这个问题通过一个简化的例子更容易解释(因为我的真实情况远非"最小"):给定...
template <typename T>
void post_in_thread_pool(T&& f)
Run Code Online (Sandbox Code Playgroud)
...函数模板,我想创建一个具有树状递归结构的并行异步算法.我将使用std::count_if占位符编写下面结构的示例.我将要使用的策略如下:
如果我检查的范围的长度小于64,我将回退到顺序std::count_if功能.(0)
如果它大于或等于64,我将在线程池中生成一个在左半部分递归的作业,并在当前线程上计算该范围的右半部分.(1)
我将使用原子共享int来"等待"计算两半.(2)
我将使用原子共享int来累积部分结果.(3)
简化代码:
auto async_count_if(auto begin, auto end, auto predicate, auto continuation)
{
// (0) Base case:
if(end - begin < 64)
{
continuation(std::count_if(begin, end, predicate));
return;
}
// (1) Recursive case:
auto counter = make_shared<atomic<int>>(2); // (2)
auto cleanup = [=, accumulator = make_shared<atomic<int>>(0) /*(3)*/]
(int partial_result)
{
*accumulator …Run Code Online (Sandbox Code Playgroud) struct Y { };
struct X : std::tuple<Y> { };
int main()
{
std::get<0>(std::make_tuple(X{}));
}
Run Code Online (Sandbox Code Playgroud)
clang++当使用libc ++时,上面的代码编译并按预期工作.
上面的代码失败,都编译clang++和g++使用时的libstdc ++,错误如下:
include/c++/7.0.1/tuple:1302:36:
error: no matching function for call to ‘__get_helper<0>(std::tuple<X>&)’
{ return std::__get_helper<__i>(__t); }
~~~~~~~~~~~~~~~~~~~~~~^~~~~
include/c++/7.0.1/tuple:1290:5:
note: candidate: template<long unsigned int __i, class _Head, class ... _Tail>
constexpr _Head& std::__get_helper(std::_Tuple_impl<_Idx, _Head, _Tail ...>&)
__get_helper(_Tuple_impl<__i, _Head, _Tail...>& __t) noexcept
^~~~~~~~~~~~
include/c++/7.0.1/tuple:1290:5:
note: template argument deduction/substitution failed:
include/c++/7.0.1/tuple:1302:36:
note: ‘std::_Tuple_impl<0, _Head, _Tail ...>’ is …Run Code Online (Sandbox Code Playgroud) 给定以下两个功能:
int f() { return 0; }
int g() { return 1; }
Run Code Online (Sandbox Code Playgroud)
以下代码根据布尔值调用其中之一b:
int t0(bool b) { return (b ? &f : &g)(); }
int t1(bool b) { return b ? f() : g(); }
int t2(bool b) { return b ? t0(true) : t0(false); }
Run Code Online (Sandbox Code Playgroud)
两者g++ (trunk)并clang++ (trunk)用-std=c++2a -Ofast -march=native失败来优化下面的代码:
int main(int ac, char**) { return t0(ac & 1); }
Run Code Online (Sandbox Code Playgroud)
产生以下程序集:
Run Code Online (Sandbox Code Playgroud)main: and edi, 1 mov eax, OFFSET FLAT:f() mov …
c++ optimization function-pointers conditional-operator compiler-optimization
Consider the following code snippet:
template <typename>
struct X { };
extern template struct X<int>;
int main()
{
X<int>{};
}
Run Code Online (Sandbox Code Playgroud)
It compiles and links: live example on godbolt.org. I would expect it not to link due to the extern template declaration.
My understanding is that extern template means: "please don't instantiate this particular template specialization in this TU, it will be provided by some other TU and you can link against it".
The examples/descriptions. I've seen on isocpp …
尾随返回类型允许在以下两种情况下简化代码:
从类的成员函数之一返回在类内部定义的类型:
struct X
{
using foo = int;
foo f();
};
// pre-C++11
X::foo X::f() { /* ... */ }
// trailing, doesn't require `X::` before `foo`
auto X::f() -> foo { /* ... */ }
Run Code Online (Sandbox Code Playgroud)返回复杂的类型,例如函数指针类型:
// pre-C++11
int(*g(float))(int) { /* ... */ }
// trailing, easier to read
auto f(float) -> int(*)(int) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)我正在尝试查找Standard的相关部分,以解释上述两种简化的工作方式。我已经看过[basic.lookup]并略过了trailing-return,但是找不到任何简单的方法可以解释上述转换的工作原理。
我错过了吗?
标准的哪些部分解释了以上的尾随回返型简化形式?
c++ ×10
c++14 ×4
c++11 ×3
c++17 ×2
asynchronous ×1
boost ×1
debugging ×1
decltype ×1
extern ×1
lambda ×1
libc++ ×1
libstdc++ ×1
optimization ×1
recursion ×1
return-type ×1
sanitizer ×1
stdtuple ×1
templates ×1
type-traits ×1