Why is template parameter pack used in a function argument type as its template argument list not able to be explicit specified

前端 未结 5 622
失恋的感觉
失恋的感觉 2020-12-28 12:55

I have the following piece of code:

template 
struct AAA{};

template
void f(AAA *) {}

int          


        
相关标签:
5条回答
  • 2020-12-28 13:00

    For you are using typename ...Args, the compiler doesn't know if int, int are all the template parameters in use or more are available by deducing the function argument. Therefore the function isn't instantiated yet and the compiler goes on trying to deduce all the other possible parameters for the parameter pack from the function arguments.

    In other terms, this works:

    f<int>(new AAA<int, int>);
    

    Because you are saying that the first parameter is int, but the compiler expects a parameters list and goes on trying to find more and more parameters greedily from the function argument, then it instantiates the function template.

    More or less the same happens in your case, but the compiler cannot deduce anything from nullptr_t for function arguments doesn't match. It expects a pointer to an A<...>, that is not the case when you pass in nullptr.
    This would work instead:

    template <typename, typename>
    struct AAA{};
    
    template<typename A, typename B>
    void f(AAA<A, B> *) {}
    
    int main() {
        f<int, int>(nullptr);
    }
    

    Because the compiler knows template arguments are two and you are providing all of them, there is nothing to deduce and the function can be instantiated. It also makes much more sense, for AAA accepts only two template parameters, so a parameter pack for f seems useless here.

    0 讨论(0)
  • 2020-12-28 13:03

    I want to add another solution that invokes the {} notion

    template <typename, typename>
    struct AAA{};
    
    template<typename ...Args>
    void f(AAA<Args...> *) {}
    
    int main() {
        f<int, int>({});
    }
    

    When the argument is {}, deduction for the parameter is disabled (nondeduced context), so there will be no mismatch and the parameter initialization actually produces a null pointer aswell.

    0 讨论(0)
  • 2020-12-28 13:08

    Just to add an easy solution:

    f<int, int>(nullptr); // doesn't work for the reasons explained by other answers
    (*f<int, int>)(nullptr); // OK - does what you want
    

    The latter forces the pack Args... to be {int, int}, and now the call itself isn't a call to a function template - it's just a call to a function pointer. We're calling a function that takes an AAA<int, int>*, and of course passing in nullptr is acceptable there.

    For fun, you can also add arbitrarily many *s:

    (*****f<int, int>)(nullptr); // still OK - does what you want
    

    ... but, you know... don't.

    0 讨论(0)
  • 2020-12-28 13:11

    Great answer by @skypjack.

    You need to help the compiler in deducing the function argument:

    AAA<int, int> *a = nullptr;
    f<int, int>(a); //works
    
    f<int, int>( (AAA<int, int> *)nullptr );  //even this will work.
    

    Fundamentally, nullptr represents a "no object" which can be assigned to any pointer type.

    0 讨论(0)
  • 2020-12-28 13:17

    You may think the compiler should deduce the pack as int ,int, but the C++ standard explicitly requires the behavior you observed.

    [temp.arg.explicit/9]

    Template argument deduction can extend the sequence of template arguments corresponding to a template parameter pack, even when the sequence contains explicitly specified template arguments. [ Example:

    template<class ... Types> void f(Types ... values);
    void g() {
      f<int*, float*>(0, 0, 0);     // Types is deduced to the sequence int*, float*, int
    }
    

    — end example ]

    The above means that even though some of the parameters were specified, deduction doesn't end. The parameter pack must always be expandable by argument deduction. It's as if the explicit arguments that were given are an instantiation of a template with a trailing parameter pack. When coupled with the following:

    [temp.arg.explicit/3]

    Trailing template arguments that can be deduced or obtained from default template-arguments may be omitted from the list of explicit template-arguments. A trailing template parameter pack not otherwise deduced will be deduced to an empty sequence of template arguments. ...

    The compiler must match the un-deduced arguments to an empty pack. But it has nothing to deduce it from.

    As such, your attempt to plug Args... into AAA cannot possibly match. Because the type sequence is two types with a trailing list (that the compiler cannot deduce as empty from nullptr). While AAA expects just two types.

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