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 questionthis 指针永远不是左值,因此应该具有类型 Foo*(并且 不是 Foo* const) ,并且应该绑定到 Foo*&&。这似乎是一个 MSVC 错误。

[关于使用 &*this 时的 GCC 行为,我不知道。]