我需要制作一个函数,该函数采用带有可变参数和一些固定参数的函数指针,并且无法使其在 Visual Studio 2013 上运行。我假设 Visual Studio 2013 可能缺少一些通常是案例并做了最小化的东西这个例子做了我需要的,并针对 gcc 和 clang 进行了尝试。我在所有三个编译器上得到了完全不同的结果。所以我想解决的问题是:
- 我的例子是否有效?如果不是我做错了什么?
- 如果我的例子是有效的,关于 gcc 和 clang 行为的任何提示(让我们把 msvc 算出来,因为它是一个黑盒子)?
这个例子:
#include <iostream>
struct foo
{
void work(int first, int second, int third)
{
std::cout << "0: " << first << ",1: " << second << ",2: " << third << std::endl;
}
void work_with_double(double first, int second, int third, int fourth)
{
std::cout << "0: " << first << ",1: " << second << ",2: " << third << ",3: " << fourth << std::endl;
}
};
template<typename ... argument_types>
void invoke_foo(foo* instance, int first, int second, int third, void (foo::*method)(argument_types ... arguments, int, int, int), argument_types ... arguments)
{
(instance->*method)(arguments ..., first, second, third);
}
int main(int argc, char** argv)
{
foo instance;
invoke_foo(&instance, 1, 2, 3, &foo::work); // gcc ok, clang err, msvc 2013 err
invoke_foo<>(&instance, 1, 2, 3, &foo::work); // gcc ok, clang err, msvc 2013 err
invoke_foo(&instance, 1, 2, 3, &foo::work_with_double, 1.0); // gcc err, clang ok, msvc 2013 err
invoke_foo<double>(&instance, 1, 2, 3, &foo::work_with_double, 1.0); // gcc err, clang err, msvc 2013 ok
return 0;
}
使 Visual Studio 2015(无更新)崩溃的修改片段
如果invoke_foo
作为对象的成员函数,Visual Studio 2015 会崩溃。
#include <iostream>
#include <memory>
struct foo
{
void work(int first, int second, int third, int fourth, int fifth, int sixth, int seventh, int eight)
{
std::cout << "0: " << first << ",1: " << second << ",2: " << third << std::endl;
}
void work_with_double(double firstExtra, int first, int second, int third, int fourth, int fifth, int sixth, int seventh, int eight)
{
std::cout << "0: " << first << ",1: " << second << ",2: " << third << ",3: " << fourth << std::endl;
}
};
struct bar
{
};
struct wrapper
{
template <typename T> struct non_deduced { using type = T; };
template <typename T> using non_deduced_t = typename non_deduced<T>::type;
template<typename ... argument_types>
std::shared_ptr<bar> invoke_foo(int first, int second, int third, int fourth, int fifth, int sixth, int seventh, int eight, void (foo::*method)(non_deduced_t<argument_types>... arguments, int, int, int, int, int, int, int, int), argument_types ... arguments)
{
(foo_.get()->*method)(arguments ..., first, second, third, fourth, fifth, sixth, seventh, eight);
return nullptr;
}
std::unique_ptr<foo> foo_ = std::move(std::unique_ptr<foo>(new foo));
};
int main(int argc, char** argv)
{
wrapper instance;
instance.invoke_foo(1, 2, 3, 4, 5, 6, 7, 8, &foo::work);
instance.invoke_foo(1, 2, 3, 4, 5, 6, 7, 8, &foo::work_with_double, 1.0);
}