我正在撰寫一個包裝器std::jthread和一些周圍的基礎設施。我無法理解為什么以下內容無法編譯:
#include <iostream>
#include <map>
#include <functional>
#include <thread>
// two random functions
void foo(int i) { std::cout << "foo " << i << std::endl; }
void bar(int i) { std::cout << "bar " << i << std::endl; }
// mechanism to identify them
enum function_kind {
foo_kind, bar_kind
};
std::map<function_kind, std::function<void(
int)>> kind_to_function{{foo_kind, foo},
{bar_kind, bar}};
// wrapper around jthread
// (additional functionality ommitted for brevity)
template<typename Callable, typename... Args>
class MyThread {
public:
explicit MyThread(Callable &&function, Args &&...args) : m_thread{
std::forward<Callable>(function),
std::forward<Args>(args)...} {}
private:
std::jthread m_thread;
};
int main() {
std::jthread t1(kind_to_function[foo_kind], 3); // works
MyThread t2(kind_to_function[foo_kind], 3); // complains
return 0;
}
我真的只是想模仿std::jthread我自己的班級所做的一切。
IDE(clion)抱怨說,第一個引數t2不是右值。編譯器抱怨有點復雜:
main.cpp: In function ‘int main()’:
main.cpp:29:46: error: class template argument deduction failed:
29 | MyThread t2(kind_to_function[foo_kind], 3); // complains
| ^
main.cpp:29:46: error: no matching function for call to ‘MyThread(std::map<function_kind, std::function<void(int)> >::mapped_type&, int)’
main.cpp:20:14: note: candidate: ‘MyThread(Callable&&, Args&& ...)-> MyThread<Callable, Args> [with Callable = std::function<void(int)>; Args = {int}]’ (near match)
20 | explicit MyThread(Callable &&function, Args &&...args) : m_thread{std::forward<Callable>(function),
| ^~~~~~~~
main.cpp:20:14: note: conversion of argument 1 would be ill-formed:
main.cpp:29:46: error: cannot bind rvalue reference of type ‘std::function<void(int)>&&’ to lvalue of type ‘std::map<function_kind, std::function<void(int)> >::mapped_type’ {aka ‘std::function<void(int)>’}
29 | MyThread t2(kind_to_function[foo_kind], 3); // complains
| ^
main.cpp:18:7: note: candidate: ‘template<class Callable, class ... Args> MyThread(MyThread<Callable, Args>)-> MyThread<Callable, Args>’
18 | class MyThread {
| ^~~~~~~~
main.cpp:18:7: note: template argument deduction/substitution failed:
main.cpp:29:46: note: ‘std::function<void(int)>’ is not derived from ‘MyThread<Callable, Args>’
29 | MyThread t2(kind_to_function[foo_kind], 3); // complains
| ^
在任何情況下,引數都適用于std::jthread,它也只需要右值......那么我錯過了什么?
uj5u.com熱心網友回復:
建構式的引數MyThread不是轉發參考,因為建構式不是模板。不要使類成為模板,而只是建構式:
class MyThread {
public:
template<typename Callable, typename... Args>
explicit MyThread(Callable &&function, Args &&...args) :
m_thread{
std::forward<Callable>(function),
std::forward<Args>(args)...} {}
private:
std::jthread m_thread;
};
uj5u.com熱心網友回復:
在任何情況下,引數都適用于
std::jthread,它也只需要右值......那么我錯過了什么?
jthread不是模板,它的建構式是模板。這使得對模板引數的右值參考成為轉發參考,而不是普通的右值參考。
但是,由于MyThread它本身就是一個模板,并且它的建構式不是模板建構式,所以行為就不一樣了。實體化后,它是一個只接受右值的常規建構式。
轉發參考取決于它們所屬的函式模板發生的模板引數推導。因此,非模板建構式意味著沒有轉發參考。
好的,但是您沒有為 指定模板引數MyThread,為什么似乎沒有錯誤?因為類模板引數推導允許您省略這些。CTAD 發生在它自己的多載解決步驟中,與實際選擇建構式來初始化物件完全脫節。一個步驟可能是不正確的,而另一步驟則不是。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/436694.html
