【发布时间】:2022-01-17 07:08:54
【问题描述】:
首先,我的代码:
#include <iostream>
#include <functional>
#include <string>
#include <thread>
#include <chrono>
using std::string;
using namespace std::chrono_literals;
class MyClass {
public:
MyClass() {}
// More specific constructor.
template< class Function, class... Args >
explicit MyClass( const std::string & theName, Function&& f, Args&&... args )
: name(theName)
{
runner(f, args...);
}
// Less specific constructor
template< class Function, class... Args >
explicit MyClass( Function&& f, Args&&... args ) {
runner(f, args...);
}
void noArgs() { std::cout << "noArgs()...\n"; }
void withArgs(std::string &) { std::cout << "withArgs()...\n"; }
template< class Function, class... Args >
void runner( Function&& f, Args&&... args ) {
auto myFunct = std::bind(f, args...);
std::thread myThread(myFunct);
myThread.detach();
}
std::string name;
};
int main(int, char **) {
MyClass foo;
foo.runner (&MyClass::noArgs, &foo);
foo.runner (&MyClass::withArgs, &foo, std::string{"This is a test"} );
MyClass hasArgs(string{"hasArgs"}, &MyClass::withArgs, foo, std::string{"This is a test"} );
std::this_thread::sleep_for(200ms);
}
我正在尝试围绕std::thread 构建一个包装器(插入冗长的原因列表)。考虑将MyClass 在我的实际库中命名为ThreadWrapper。
我希望能够构建一个 MyClass 作为std::thread 的直接替代品。这意味着能够做到这一点:
MyClass hasArgs(&MyClass::withArgs, foo, std::string{"This is a test"} );
但我也想选择给线程一个名字,像这样:
MyClass hasArgs(string{"hasArgs"}, &MyClass::withArgs, foo, std::string{"This is a test"} );
所以我创建了两个模板构造函数。如果我只想做一个或另一个并且只使用一个模板构造函数,我正在做的很好。
使用编写的代码,如果你编译 (g++),你会得到严重的错误。如果我注释掉更具体的构造函数,我会得到一组不同的讨厌的错误。如果我注释掉不太具体的构造函数(没有const std::string & arg 的构造函数),那么我正在尝试做的一切工作。也就是说,std::string 是正确的,并且有效。
发生的情况是,如果我有两个构造函数,编译器每次都会选择不太具体的一个。我想强迫它使用更具体的。我想我可以在 C++ 17 中使用 Trait 做到这一点,但我从未使用过它们,而且我不知道从哪里开始。
现在,我将只使用更具体的版本(带有名称的版本)并继续前进。但是我想把不太具体的那个放回去,当我不关心线程名称时使用它。
但是有什么方法可以让我同时拥有两个模板并让编译器根据第一个参数是std::string 还是可以转换为一个来确定哪个模板?
没有人应该在这方面花费大量时间,但如果你看到这个并说,“哦,乔只需要……”那么我很乐意提供帮助。否则我只能忍受这不是 100% 的直接替代品,这很好。
【问题讨论】: