Home > Net >  template parameter default value with dependancy to deduced template parameters
template parameter default value with dependancy to deduced template parameters

Time:01-24

I am aware this question is quite similar to This post, however the cited post was about class template argument deduction. Here my question is about function template argument deduction.

I currently have the following piece of code, which enables users to specify the algorithm a method should use in order to compute some values. (Using a strategy Pattern is not applicable in this case for various reasons which are not relevant here)

#include <iostream>
#include <typeinfo>
template<typename T>
class BasicStrategy
{
    public:
    BasicStrategy(T& i_Input)
    {
        std::cout << "Applying Basic Strategy to type : " << typeid(T).name() << " With value : " << i_Input <<std::endl;
    }
};

template<typename T>
class ComplexStrategy
{
    public:
    ComplexStrategy(T& i_Input)
    {
        std::cout << "Applying Complex Strategy to type : " << typeid(T).name() << " With value : " << i_Input <<std::endl;
    }
};

template<typename T, typename STRATEGY = BasicStrategy<T>>
void Func(T& i_Input)
{
    STRATEGY MyStrategy(i_Input);
}


int main()
{
    int i = 12;
    double d = 24;
    
    Func(i);
    Func(d);

    Func<int, ComplexStrategy<int>>(i);
    Func<double, ComplexStrategy<double>>(d);
    return 0;
}

I would like to know if it would be possible to simplify the interface of "Func()" in order to exempt the user from specifying redundant types if not using the "BasicStrategy" For instance, the "ideal" interface would look like this (i realize this is not possible though):

int main()
{
    int i = 12;
    double d = 24;

    Func(i);
    Func(d);

    Func<ComplexStrategy>(i);
    Func<ComplexStrategy>(d);
    return 0;
}

Of course, i could declare Func() like this

template<typename STRATEGY, typename T>
void Func(T& i_Input)

Which would not require the user to specify the type T twice, however, this prevents me from assigning a default strategy to the method, which would break a lot of existing code and making it less readable overall.

Is there a clean solution to this problem or is this a choice i have to make between the two options?

CodePudding user response:

You can use a template template parameter to achieve exactly what you want:

template<template <typename> typename Strategy = BasicStrategy, typename T>
void Func(T& i_Input)
{
    Strategy<T> MyStrategy(i_Input);
}

That way what you mentioned as ideal would work: https://godbolt.org/z/aosPzqa3r

CodePudding user response:

i realize this is not possible though

It is when you make STRATEGY a template template argument.

#include <iostream>
#include <typeinfo>
template<typename T>
class BasicStrategy
{
    public:
    BasicStrategy(T& i_Input)
    {
        std::cout << "Applying Basic Strategy to type : " << typeid(T).name() << " With value : " << i_Input <<std::endl;
    }
};

template<typename T>
class ComplexStrategy
{
    public:
    ComplexStrategy(T& i_Input)
    {
        std::cout << "Applying Complex Strategy to type : " << typeid(T).name() << " With value : " << i_Input <<std::endl;
    }
};
template <template<typename> typename STRATEGY = BasicStrategy, typename T>
void Func(T& i_Input)
{
    STRATEGY<T> MyStrategy(i_Input);
}


int main()
{
    int i = 12;
    double d = 24;
    
    Func(i);
    Func(d);

    Func<ComplexStrategy>(i);
    Func<ComplexStrategy>(d);
    return 0;
}

Live Demo

CodePudding user response:

Using a template template parameter for the strategy and auto for the function parameter allows you to get the syntax you want. Doing so gives you

template<template<typename> typename STRATEGY = BasicStrategy>
void Func(auto& i_Input)
{
    STRATEGY MyStrategy(i_Input);
}

Using your example of

int main()
{
    int i = 12;
    double d = 24;
    
    Func(i);
    Func(d);

    Func<ComplexStrategy>(i);
    Func<ComplexStrategy>(d);
    return 0;
}

it outputs

Applying Basic Strategy to type : i With value : 12
Applying Basic Strategy to type : d With value : 24
Applying Complex Strategy to type : i With value : 12
Applying Complex Strategy to type : d With value : 24

CodePudding user response:

You may switch to use functor separating Strategy from T:


template<template<typename T> typename STRATEGY = BasicStrategy>
struct t_Func
{
    template<typename T>
    void operator ()(T& i_Input) const
    {
        STRATEGY<T> MyStrategy(i_Input);
    }
};

template<template<typename T> typename STRATEGY = BasicStrategy>
constexpr t_Func<STRATEGY> Func{};

int main()
{
    int i = 12;
    double d = 24;
    
    Func<>(i);
    Func<>(d);

    Func<ComplexStrategy>(i);
    Func<ComplexStrategy>(d);
    return 0;
}

online compiler

  • Related