Home > front end >  Is it possible to deduct the template type of a templated parameter in C ?
Is it possible to deduct the template type of a templated parameter in C ?

Time:03-25

I have a template class, with an internal method that is itself templated.

Consider the following minimal working example

#include <functional>

template<typename T>
class P{
public:
    template <typename U>
    P<U> call(std::function< P<U> (T)> f){
        return f(return_value);
    }
    T return_value;
};

P<int> foo() {
    P<int> value = P<int>();
    return value;
}

P<float> bar(int arg) {
    return P<float>();
}

int main()
{
    auto res = foo().call<float>(bar);

    return 0;
}

As you can see in the main function, the compiler forces me to to specify the float type for calling the call() function, eventhough the type should be obvious from passing over the bar() function, that specifies the float type.

Is it somehow possible to deduct the type so that the code in the main function can be simplified to the following statement:

auto res = foo().call(bar);

CodePudding user response:

std::function is not the type that you should use whenever you want to pass a function around. std::function is a type that uses type erasure to be able to store different types of callables in one type. If you don't need that then you need no std::function:

#include <functional>

template<typename T>
class P{
public:
    template <typename F>
    auto call(F f){
        return f(return_value);
    }
    T return_value{};  // don't forget to initialize !
};

P<int> foo() {
    P<int> value = P<int>();
    return value;
}

P<float> bar(int arg) {
    return P<float>();
}

int main()
{
    auto res = foo().call(bar);

    return 0;
}

Using partial specializatzion you can get the return type of bar and you can get the float from P<float>:

#include <type_traits>
#include <iostream>

template <typename T> class P;

// get return type from function
template <typename T> struct return_type;

template <typename R,typename...args>
struct return_type<R(args...)> { using type = R; };

// get T from P<T>
template <typename P> struct P_arg;   
template <typename T> struct P_arg< P<T> > { using type = T; };

// combine both
template <typename F>
struct get {
    using type = typename P_arg<typename return_type<F>::type >::type;
};

template<typename T>
class P{
public:
    template <typename F>
    auto call(F f){
        return f(return_value);
    }
    T return_value{};
};

P<float> bar(int arg) {
    return P<float>();
}

int main()
{
    std::cout << std::is_same_v< get<decltype(bar)>::type,float>;
    return 0;
}

Though that does not really help here, because you cannot use it to decalre the return type of P::call, as it requires P<float> to be already complete.

  • Related