Different results on the example of variation patterns among gcc, clang and msvc - can anyone explain?

I needed to make a function that, after starting, pointed to a function with variable arguments and some fixed arguments and could not make it work on Visual Studio 2013. I assumed that perhaps Visual Studio 2013 is missing something that often happens and made a minimal example that did what I needed and tried it against gcc and clang. And I have all different results for all three compilers. Therefore, the issues that I would like to solve are the following:

  • Is my example valid? If not what am I doing wrong?
  • If my example is valid, any hints about the behavior of gcc and clang (allows you to read msvc due to the black box)?

Example:

#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);
}
+4
1

, argument_types method, , , .

void (foo::*method)(argument_types ... arguments, int, int, int)
                    ^^^^^^^^^^^^^^^^^^ can't infer here
                                                ^^^^^^^^^^^^^^^ because of these

, argument_types , identity:

template<class T> struct identity { using type = T; };
template<class T> using identity_t = typename identity<T>::type;

// ...

template<typename ... argument_types>
void invoke_foo(foo* instance, int first, int second, int third,
    void (foo::*method)(identity_t<argument_types> ... arguments, int, int, int), argument_types ... arguments)
//                      ^^^^^^^^^^^ fix here

​​ ? , (, ); , , , , - . [temp.deduct.type], :

5 - : [...]

  • , -.

6 - , , , , . , .

argument_types method, invoke_foo.

, , ICC ( Intel ++); ICC , gcc. , , , , , , ​​ , - . ( -) , argument_types method, , .

, , :

  • gcc , argument_types method, ;
  • clang , argument_types , ;
  • MSVC argument_types , , , ;
  • ICC , argument_types , .
+4

All Articles