Howard
Howard

Reputation: 218

Template Type != Deduced type

I'm attempting to give a friendly name to a type as a template typename because I need to use the name in a few places within the function. The type is being deduced based on the number of other template arguments in the parameter pack, as shown below:

#include <cassert>
#include <functional>
#include <type_traits>

template < typename ... TArgs, typename Functor = std::function< std::conditional_t< sizeof...(TArgs) == 0, int (), int (TArgs...) > > >
void DoStuff(const Functor & func, TArgs ... args) {
    if constexpr (sizeof...(TArgs) == 0)
        assert(typeid(Functor).hash_code() == typeid(std::function<int ()>).hash_code());
    else
        assert(typeid(Functor).hash_code() == typeid(std::function<int (TArgs...)>).hash_code());
}

int main(int argc, char * argv[]) {
    DoStuff([] () { return 5; });
    DoStuff([] (int a) { return a; });

    return 0;
}

This compiles just fine, but both assertions fail because the alias Functor is not actually a std::function<>. On the other hand, if I change the code to repeat the definition of Functor in the typeid calls it works perfectly, like below:

#include <cassert>
#include <functional>
#include <type_traits>

template < typename ... TArgs, typename Functor = std::function< std::conditional_t< sizeof...(TArgs) == 0, int (), int (TArgs...) > > >
void DoStuff(const Functor & func, TArgs ... args) {
    if constexpr (sizeof...(TArgs) == 0)
        assert(typeid(std::function< std::conditional_t< sizeof...(TArgs) == 0, int (), int (TArgs...) > >).hash_code() == typeid(std::function<int ()>).hash_code());
    else
        assert(typeid(std::function< std::conditional_t< sizeof...(TArgs) == 0, int (), int (TArgs...) > >).hash_code() == typeid(std::function<int (TArgs...)>).hash_code());
}

int main(int argc, char * argv[]) {
    DoStuff([] () { return 5; });
    DoStuff([] (int a) { return a; });

    return 0;
}

Why is the first declaration (using the typname Functor = ...) incorrect? Is there a different way to make that alias? Note that in answering the second question, it is OK if the solution is a const expression, the examples are only not constexpr because of the use of typeid.

Upvotes: 0

Views: 134

Answers (1)

Barry
Barry

Reputation: 302892

Why is the first declaration (using the typename Functor = ...) incorrect?

You're providing a default type for the template parameter Functor. But the default type is only used if the type is not otherwise specified or deduced. In this case, template deduction will deduce Functor in both cases to be whatever the unique type of the lambda is that it is invoked with (while Args... deduces as an empty pack).

This is similar to default function arguments not being used when they are provided.

I'm not sure what your assert()s are supposed to accomplish, but if you're checking types you should use static_assert.

Upvotes: 1

Related Questions