g++ doesn't like template method chaining on template var?

后端 未结 3 1252
天涯浪人
天涯浪人 2021-01-13 10:23

I\'m trying to compile with g++ some code previously developed under Visual C++ 2008 Express Edition, and it looks like g++ won\'t let me call a template m

相关标签:
3条回答
  • 2021-01-13 10:33

    could you try with?

    template<typename T>
    int do_outer(T& val)
    {
      return val.get_inner().template get<int>();
    }
    

    I don't have access to gcc atm, but I've had similar issues and adding the template keyword always solved them. And it works in VS too.

    0 讨论(0)
  • 2021-01-13 10:40

    Just to give some background on why the template keyword is needed:

    template<typename T>
    int do_outer(T& val)
    {
      int i;
      val.get_inner().get<int>(i);
      return i;
    }
    

    When the compiler sees this function, it does not know what the type of val is. It therefore parses the line val.get_inner().get(i) as follows:

    1: val .

    The compiler sees the . and so can assume that 'val' has class type and the next identifier is the name of a member object or function.

    2. val . get_inner (

    get_inner is the name of the member and then the compiler sees the (. The only possibility is that get_inner is a function name and so this is a function call. It then parses the parameters until it finds the closing ).

    3. val . get_inner () .

    As for the first step, it now knows that the return from get_inner must be a class type so it knows that the next identifier is a member object or function.

    4. val . get_inner () . get <

    So, what can the < possibly mean? Of course it's the start of template arguments...or maybe it's the less than operator?

    We know that get can only be an object or a function. If it is an object then the < makes perfect sense as the less than operator. Furthermore, the standard more or less states that only where the name before the < is a template-name will it treat the < as template arguments (14.2/3):

    After name lookup (3.4) finds that a name is a template-name, if this name is followed by a <, the < is always taken as the beginning of a template-argument-list and never as a name followed by the less-than operator.

    In this case, the compiler has no idea what the type of the expression val.get_inner() is and so it cannot lookup get. It more or less assumes then that it's a member object and not a template-name. '<' is treated as the less than operator and the compiler ends up checking if get is less than int - hence the error.

    So, why do the fixes work?

    Adding the template keyword

    Literally we're telling the compiler that the get is a template-name and so the < operator is treated as the start of a template argument list.

    Removing the template-arguments

    When do_outer doesn't have the template arguments ie: val . get_inner () . get ( the compiler expects that the member get is an object or a function. The ( disambiguates between these two and the name is treated as a function. Later template argument deduction then works out the type of the template parameter.

    0 讨论(0)
  • 2021-01-13 10:40

    I can't claim to be one of the, oh 10 people on the planet who fully understand C++ templates, but what you're doing here looks fine to me. (It fails with GCC 4.4.1 with the same error, BTW).

    Changing do_outer to

    const Inner& inner = val.get_inner();
    return inner.get<int>();
    

    works with GCC and presumably will also work with Visual C++.

    You might consider filing a bug with GCC; either they'll fix it, or it will be closed as INVALID and in the process someone will hopefully explain why what you're doing is not valid code.

    A further update and AHA: It turns out it's not actually valid code, GCC just gives a horrible error message. Intel C++ outputs the (actually helpful!) error message:

    template.cpp(24): error: type name is not allowed
        return val.get_inner().get<int>();
    

    Which made me realize the problem. Changing do_inner to

      return val.get_inner().template get<int>();
    

    the code is accepted by both ICC and GCC.

    0 讨论(0)
提交回复
热议问题