C++11:无法将参数从 'T *const' 转换为 'T *&&'
C++11: cannot convert argument from 'T *const' to 'T *&&'
我有可变参数模板 class 表示带有函数和输入参数的线程。
template<typename F> class my_thread;
template<typename Return, typename... Input>
class my_thread<Return(Input...)>
{
template<typename F>
my_thread(F&& f, Input&&... value) : /* mainly std::forward<Input>... to std::tuple<Input...> */ { }
}
现在,实例化class对于全局函数来说很简单
int fnc(int, double);
my_thread<int(int, double)> thr(fnc, 42, 3.14);
对于某些 class.
的函数成员来说(显然)没那么简单
my_thread<int(int, double)> thr(&Foo::fnc, 42, 3.14); // won't work, unless Foo::fnc is static.
我知道,std::thread
有一些机制(可能是部分特化),允许传递非静态成员函数,如果在所有参数之前,指针指向 class 通过 (std::thread(&Foo::bar, Foo(), 42, 3.14); // OK
)。我无法找到如何做到这一点,所以我的 my_thread
需要传递静态成员函数,并且指向 class 实例的指针必须是该函数的显式参数。
struct Dog
{
void bark();
static void bark(Dog* dog)
{
dog->bark();
}
}
这是我不得不忍受的事情,但这不是问题。
问题是用那个函数实例化 my_thread
。我将 my_thread<int(Foo*, double)> thr(&Foo::bar, this, 3.14);
写入 Visual Studio 2015,它抱怨
error C2664: 'my_thread<int (Foo *, double)>::my_thread(my_thread<int (Foo *, double)> &&)': cannot convert argument 2 from 'Foo *const ' to 'Foo *&&'
我尝试了一些施法魔法,但后来我发现,传递 &*this
而不是 this
是可行的。
我很高兴找到解决方案(或者至少是在 Windows 上编译和 运行 的东西),我决定在 linux 上用 G++ 尝试一下。我使用了相同的代码(使用 &*this
),但是 G++ 对我很生气,因为
In member function 'void Foo::SomeFunction()':
error: no matching function for call to ‘my_thread<int(Foo*,
double)>::my_thread(int (*)(Foo*, double), Foo* const, double&)’
note: candidates are: my_thread(F&&, Input&&...)
note: template argument deduction/substitution failed:
note: cannot convert ‘this’ (type ‘Foo* const’) to type ‘Foo*&&’
我很惊讶我得到了与以前几乎相同的错误。我将 &*this
编辑回 this
并且我能够在 linux.
下在 G++ 上编译和 运行
我的问题是:
谁是对的? G++ 4.9.2 还是 MVS2015?怎么解决,让我的代码在两个平台上都能运行?
或者,我是否使用了错误的方法? std::thread 是如何实现的,这样它就知道,当传递非静态成员函数时,它将需要指向该 class 实例的指针作为参数?
编辑
我正在添加更多代码,这样我的意图会更清楚。
template<typename F> struct my_thread; // std::function like syntax
template<typename Return, typename... Input>
struct my_thread<Return(Input...)>
{
struct thread_data
{
template<typename F>
thread_data(F&& _func, Input&&... _input) : func(std::forward<F>(_func)), input(std::forward<Input>(_input)...) { }
std::function<Return(Input...)> func;
std::tuple<Input...> input;
};
template<typename F>
my_thread(F&& _func, Input&&... _input) : data(std::forward<F>(_func), std::forward<Input>(_input)...) { }
thread_data data;
};
会不会是传入的指针的const'ness导致编译器不允许转换?在您的情况下,如果您假设 Foo &&,那么您将收到对指针的引用或临时指针,但在任何一种情况下,它都是您可以实际修改的值的指针。一个在你拥有它的意义上是 const 的指针,不能改变它指向的东西,例如,指针本身的目的地被卡住了。关于指针,有两种 const:一种用于指针本身,一种用于指向的内容。分别写在变量声明中“”的左右两边"const"。
这里:
template<typename F>
my_thread(F&& f, Input&&... value)
您不是在推导 "universal references",而是对 Input...
参数的右值引用(这是您想要的吗?)。在这里,对于 Input = Foo*, double
,您的构造函数读取
template<typename F>
my_thread(F&& f, Foo*&& value1, double&& value2)
这解释了 Foo*&&
部分。现在,根据 this question,this
指针永远不是左值,因此应该具有类型 Foo*
(并且 不是 Foo* const
) ,并且应该绑定到 Foo*&&
。这似乎是一个 MSVC 错误。
[关于使用 &*this
时的 GCC 行为,我不知道。]
我有可变参数模板 class 表示带有函数和输入参数的线程。
template<typename F> class my_thread;
template<typename Return, typename... Input>
class my_thread<Return(Input...)>
{
template<typename F>
my_thread(F&& f, Input&&... value) : /* mainly std::forward<Input>... to std::tuple<Input...> */ { }
}
现在,实例化class对于全局函数来说很简单
int fnc(int, double);
my_thread<int(int, double)> thr(fnc, 42, 3.14);
对于某些 class.
的函数成员来说(显然)没那么简单my_thread<int(int, double)> thr(&Foo::fnc, 42, 3.14); // won't work, unless Foo::fnc is static.
我知道,std::thread
有一些机制(可能是部分特化),允许传递非静态成员函数,如果在所有参数之前,指针指向 class 通过 (std::thread(&Foo::bar, Foo(), 42, 3.14); // OK
)。我无法找到如何做到这一点,所以我的 my_thread
需要传递静态成员函数,并且指向 class 实例的指针必须是该函数的显式参数。
struct Dog
{
void bark();
static void bark(Dog* dog)
{
dog->bark();
}
}
这是我不得不忍受的事情,但这不是问题。
问题是用那个函数实例化 my_thread
。我将 my_thread<int(Foo*, double)> thr(&Foo::bar, this, 3.14);
写入 Visual Studio 2015,它抱怨
error C2664: 'my_thread<int (Foo *, double)>::my_thread(my_thread<int (Foo *, double)> &&)': cannot convert argument 2 from 'Foo *const ' to 'Foo *&&'
我尝试了一些施法魔法,但后来我发现,传递 &*this
而不是 this
是可行的。
我很高兴找到解决方案(或者至少是在 Windows 上编译和 运行 的东西),我决定在 linux 上用 G++ 尝试一下。我使用了相同的代码(使用 &*this
),但是 G++ 对我很生气,因为
In member function 'void Foo::SomeFunction()': error: no matching function for call to ‘my_thread<int(Foo*, double)>::my_thread(int (*)(Foo*, double), Foo* const, double&)’
note: candidates are: my_thread(F&&, Input&&...)
note: template argument deduction/substitution failed:
note: cannot convert ‘this’ (type ‘Foo* const’) to type ‘Foo*&&’
我很惊讶我得到了与以前几乎相同的错误。我将 &*this
编辑回 this
并且我能够在 linux.
我的问题是:
谁是对的? G++ 4.9.2 还是 MVS2015?怎么解决,让我的代码在两个平台上都能运行?
或者,我是否使用了错误的方法? std::thread 是如何实现的,这样它就知道,当传递非静态成员函数时,它将需要指向该 class 实例的指针作为参数?
编辑
我正在添加更多代码,这样我的意图会更清楚。
template<typename F> struct my_thread; // std::function like syntax
template<typename Return, typename... Input>
struct my_thread<Return(Input...)>
{
struct thread_data
{
template<typename F>
thread_data(F&& _func, Input&&... _input) : func(std::forward<F>(_func)), input(std::forward<Input>(_input)...) { }
std::function<Return(Input...)> func;
std::tuple<Input...> input;
};
template<typename F>
my_thread(F&& _func, Input&&... _input) : data(std::forward<F>(_func), std::forward<Input>(_input)...) { }
thread_data data;
};
会不会是传入的指针的const'ness导致编译器不允许转换?在您的情况下,如果您假设 Foo &&,那么您将收到对指针的引用或临时指针,但在任何一种情况下,它都是您可以实际修改的值的指针。一个在你拥有它的意义上是 const 的指针,不能改变它指向的东西,例如,指针本身的目的地被卡住了。关于指针,有两种 const:一种用于指针本身,一种用于指向的内容。分别写在变量声明中“”的左右两边"const"。
这里:
template<typename F>
my_thread(F&& f, Input&&... value)
您不是在推导 "universal references",而是对 Input...
参数的右值引用(这是您想要的吗?)。在这里,对于 Input = Foo*, double
,您的构造函数读取
template<typename F>
my_thread(F&& f, Foo*&& value1, double&& value2)
这解释了 Foo*&&
部分。现在,根据 this question,this
指针永远不是左值,因此应该具有类型 Foo*
(并且 不是 Foo* const
) ,并且应该绑定到 Foo*&&
。这似乎是一个 MSVC 错误。
[关于使用 &*this
时的 GCC 行为,我不知道。]