Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parameter pack with default template argument

In this code, I'm trying to generalize Test from using Arg to using Args.... The problem is the default template argument. What I have below compiles, except when I uncomment the commented-out line in main():

#include <iostream>
#include <type_traits>

struct A {
    void foo(int) const {}
    void foo(int, bool, char) const {}
};

template <typename...> struct voider { using type = void; };

template <typename... Ts>
using void_t = typename voider<Ts...>::type;

template <typename T, typename Arg, typename = void_t<T>>
struct Test : std::false_type {};

template <typename T, typename Arg>
struct Test<T, Arg, void_t<decltype(std::declval<T&>().foo(std::declval<Arg>()))>> :
    std::true_type {};

// Trying to generalize Test with Args... instead of Arg
template <typename T, typename, typename... Args> struct Check;

template <typename T, typename... Args>
struct Check<T, void_t<T>, Args...> : std::false_type {};

template <typename T, typename... Args>
struct Check<T, void_t<decltype(std::declval<T&>().foo(std::declval<Args>()...))>, Args...>
    : std::true_type {};

template <typename T, typename... Args>
using CheckArgs = Check<T, void_t<T>, Args...>;

int main() {
    std::cout << std::boolalpha << Test<A, int>::value << '\n';  // true
//  std::cout << CheckArgs<A, int, bool, char>::value << '\n';  // ambiguous
}

The last line in main() is ambiguous. Firstly, why is it ambiguous, while the first line in main() is not? And secondly, how to fix the code so that the last line in main will compile (it is supposed to evaluate to true since int, bool, char are arguments of A::foo)?

like image 290
prestokeys Avatar asked Sep 16 '15 23:09

prestokeys


People also ask

CAN default arguments be used with the template?

You cannot give default arguments to the same template parameters in different declarations in the same scope. The compiler will not allow the following example: template<class T = char> class X; template<class T = char> class X { };

Can template parameters have default values?

Just like in case of the function arguments, template parameters can have their default values. All template parameters with a default value have to be declared at the end of the template parameter list.

Can a template be a template parameter?

Templates can be template parameters. In this case, they are called template parameters. The container adaptors std::stack, std::queue, and std::priority_queue use per default a std::deque to hold their arguments, but you can use a different container. Their usage is straightforward.

What is a template template parameter in C++?

In C++ this can be achieved using template parameters. A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.


1 Answers

You want

template <typename T, typename, typename... Args> 
struct Check : std::false_type {};

template <typename T, typename... Args>
struct Check<T, void_t<decltype(std::declval<T&>().foo(std::declval<Args>()...))>, Args...>
    : std::true_type {};

You want the primary template to provide the default case - which is false, and the partial specialization to supply the true case. When you write two partial specializations, both are viable, and there's no ordering between the two, so it ends up being ambiguous

And this is just reimplementing a more constrained version of std::experimental::is_detected.

like image 132
T.C. Avatar answered Oct 13 '22 01:10

T.C.