2

I am using a variadic template function where the function parameters isn't the templated types.

I got a compilation error:

Error C2668 '_TailHelper': ambiguous call to overloaded function

Here it is the code snippet.

template <typename HEAD>
void _TailHelper(int) {
    std::cout << typeid(HEAD).name() << std::endl;
}

template <typename HEAD, typename ... TAILS>
void _TailHelper(int x) {
    _TailHelper<HEAD>(x);
    _TailHelper<TAILS...>(x);
}


int main(){
    _TailHelper<int,double>(2);
}
  • 1
    You forgot to explain how you are compiling and quote the compiler's error in full. – underscore_d Oct 05 '20 at 10:15
  • 3
    names starting with `_` followed by a captial letter are reserved. – 463035818_is_not_an_ai Oct 05 '20 at 10:20
  • what should `_TailHelper(x);` call? Your compiler does not know and we also cannot – 463035818_is_not_an_ai Oct 05 '20 at 10:21
  • 2
    Of course it is ambiguous, `_TailHelper` matches both templates, `TAILS` can be empty. – Quimby Oct 05 '20 at 10:23
  • Also, please don't `SHOUT` in anything except `MACRO_NAMES`, and don't use macros either. If you want a convention that makes template arguments stand out from other names, then try e.g. `T_Head` and `T_Tails` or something, but not `ALL_CAPS`. – underscore_d Oct 05 '20 at 10:37
  • @underscore_d I don't think a condescending tone is warranted when you are merely expressing your opinion. – ypnos Oct 05 '20 at 10:51
  • @ypnos I fail to see what is condescending about saying "please" and just repeating two very common recommendations. – underscore_d Oct 05 '20 at 11:02
  • Your 'please' would have been great in your first comment. If I were to write your second comment, I would feel more comfortable suggesting a style than asking for a style, even if I feel it is somewhat established. I would also link a resource like https://stackoverflow.com/questions/692752/naming-conventions-for-template-types Your comments are both helpful, but the wording put me off. – ypnos Oct 05 '20 at 11:16

3 Answers3

5

Both overloads match with single template argument, so you have to disable one. For example like that:

#include <iostream>    
#include <typeinfo>

template <typename T>
void TailHelper(int) { 
    std::cout << typeid(T).name() << std::endl;
}

template <typename HEAD, typename ... TAILS>
typename std::enable_if<(sizeof...(TAILS) != 0)>::type
TailHelper(int x) {
    TailHelper<HEAD>(x);        
    TailHelper<TAILS...>(x);
}

int main() {
    TailHelper<int,double>(2);
}
Öö Tiib
  • 10,809
  • 25
  • 44
0

The ambiguous call comes from this line:

_TailHelper<HEAD>(x);

this call matches both functions the first one, and the second function which its second parameter can refer to zero or more template parameters.

avish
  • 48
  • 6
0

As alternative to recursion, you might "loop" over your variadic:

In C++17:

template <typename... Ts>
void PrintTypes() {
    ((std::cout << typeid(Ts).name() << std::endl), ...);
}

In previous version, it is less elegant, and you might use some trick as:

template <typename... Ts>
void PrintTypes() {
    const int dummy[] = {0, ((std::cout << typeid(Ts).name() << std::endl), 0)...};
    static_cast<void>(dummy); // Avoid warning for unused variable
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302