rubenvb
rubenvb

Reputation: 76785

Why is this code complaining about "a non-type template parameter cannot have type"?

The code:

#include <functional>
#include <type_traits>

namespace impl
{
    // lame recursive implementation
    template<typename Functor, Functor F, typename T, T OneValue, T SecondValue, T... Values>
    struct variadic_conjunction : variadic_conjunction<Functor, F, T, F(OneValue, SecondValue), Values...> {};

    template<typename Functor, Functor F, typename T, T OneValue, T SecondValue>
    struct variadic_conjunction<Functor, F, T, OneValue, SecondValue> : std::integral_constant<T, F(OneValue, SecondValue)> {};
}

template<typename Functor, Functor F, typename T, T... Values>
struct variadic_conjunction : impl::variadic_conjunction<Functor, F, T, Values...> {};

template<typename Functor, Functor F, typename T, T... Values>
constexpr T variadic_conjunction_v = variadic_conjunction<Functor, F, T, Values...>::value;

template<typename T, T... Values>
struct variadic_max : variadic_conjunction<std::greater<T>, std::greater<T>{}, T, Values...> {};

template<typename T, T... Values>
constexpr T variadic_max_v = variadic_max<T, Values...>::value;

int main()
{
    constexpr auto max = variadic_max_v<std::size_t, 4, 8>;
}

You can play with it on coliru: http://coliru.stacked-crooked.com/a/17c5065229594de9.

It complains about this:

main.cpp:14:36: error: a non-type template parameter cannot have type 'std::__1::greater<unsigned long>'
template<typename Functor, Functor F, typename T, T... Values>
                                   ^
main.cpp:21:23: note: while substituting prior template arguments into non-type template parameter 'F' [with Functor = std::__1::greater<unsigned long>]
struct variadic_max : variadic_conjunction<std::greater<T>, std::greater<T>{}, T, Values...> {};
                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:24:30: note: in instantiation of template class 'variadic_max<unsigned long, 4, 8>' requested here
constexpr T variadic_max_v = variadic_max<T, Values...>::value;
                             ^
main.cpp:28:26: note: in instantiation of variable template specialization 'variadic_max_v<unsigned long, 4, 8>' requested here
    constexpr auto max = variadic_max_v<std::size_t, 4, 8>;
                         ^
main.cpp:28:26: error: constexpr variable 'max' must be initialized by a constant expression
    constexpr auto max = variadic_max_v<std::size_t, 4, 8>;
                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2 errors generated.

But as far as I can tell, I'm passing an instance of std::greater<T> (note the brace initialization {}).

I'm also unsure about the second error, but I'll get to it later.

Upvotes: 1

Views: 3459

Answers (2)

Doot
Doot

Reputation: 745

Looking at https://en.cppreference.com/w/cpp/container/priority_queue, it uses

template<
    class T,
    class Container = std::vector<T>,
    class Compare = std::less<typename Container::value_type>
> class priority_queue;

We can see that Compare uses typename/class, not std::function<...> This is because std::greater is a struct:

template< class T = void >
struct greater;

Upvotes: 1

Andrei R.
Andrei R.

Reputation: 2462

You are trying to parametrize template with std::greater<T> which is not an acceptable type for template parameter (cppreference):

  • std::nullptr_t (since C++11)
  • integral type (note: bool is integral type)
  • lvalue reference type (to object or to function);
  • pointer type (to object or to function);
  • pointer to member type (to member object or to member function);
  • enumeration type.

Upvotes: 6

Related Questions