Ambiguous Function Calls to C++ base classes

前端 未结 3 407
旧巷少年郎
旧巷少年郎 2021-02-05 11:53

I\'m trying to create a variadic templated class which provides a method for each class in the typelist. An example is shown below which creates a print method for

3条回答
  •  既然无缘
    2021-02-05 12:22

    The following code can resolve the ambiguity problem:

    #include 
    #include 
    
    // Helper class providing a function call
    template 
    class PrintHelper
    {
      protected:
        void print_impl(const T& t) { std::cout << t << std::endl; }
    };
    
    // Provides a print method for each type listed
    template 
    class Printer : public PrintHelper...
    {
      public:
        template 
        void print(const U& u) { 
          PrintHelper::print_impl(u); 
        };
    };
    
    int main()
    {
        Printer p;
        p.print(std::string("Hello World")); // Ambiguous Call
    }
    

    Which is not very nice because of the requirement that the type U (deduced on call) is exactly one of the types in the variadic type list. You might be able to fancy things up a bit to solve that issue. With a bit of template magic and Sfinae, you can probably solve this fairly easily (but it is surely not as neat and clean).

    The ambiguity problem is not related to the use of template or variadic templates, of course, it is a straight-forward application of the member lookup rules (Section 10.2/2 of the standard), i.e., the often-called "member hiding rules". If you take this simpler non-template version, you will get the same ambiguity problem, but with a very simple solution to it:

    struct IntPrinter {
      void print(const int& i) { std::cout << i << std::endl; };
    };
    
    struct StringPrinter {
      void print(const std::string& s) { std::cout << s << std::endl; };
    };
    
    struct IntStringPrinter : IntPrinter, StringPrinter {
      using IntPrinter::print;       // These using-statements will solve the problem
      using StringPrinter::print;    // by importing all 'print' functions to the same 
                                     // overload resolution level.
    };
    

    So, the problem here is really that the ambiguity arises before the compiler even tries to apply normal overload-resolution rules, because it first tries to figure out which branch of the inheritance to follow to find the member function(s), and then, it will resolve the overload at one inheritance level only. And the problem when using variadic templates is that there doesn't seem to be any way to unpack a set of "using" statements to import all the print functions up to the same inheritance level. If anyone knows of a way to unpack such using-statements, I'm all ears. You might have to fall back to pre-variadic-template solutions (like a general template with 10 arguments, and specialize for all ten versions).

提交回复
热议问题