c++templatestemplate-argument-deduction

Deducing template parameter


I have a class Tester which is inherited from class Usual or Special. It depends on a template parameter useSpecial. By default, it uses Usual, but if the user wants, he can use Special instead.

This is my code:

#include <iostream>
#include <vector>

class Usual
{
protected:
    int res() { return 0; }
};

class Special
{
protected:
    int res() { return 1; }
};

enum class UseSpecial { No, Yes };

template<typename Container, UseSpecial useSpecial = UseSpecial::No>
class Tester : public 
    std::conditional_t<useSpecial == UseSpecial::No, Usual, Special> 
{
public:
using ParentType = std::conditional_t<useSpecial == UseSpecial::No, Usual, Special>;

Tester(Container&& cont) : cont_(std::move(cont)) 
{}

int Call() { return ParentType::res() + cont_.size(); }

private:
Container cont_;
};

int main()
{
    std::vector vec1{1.1, 2.2, 3.3};
    Tester tester1(std::move(vec1));
    
    std::vector vec2{1, 2, 3};
    Tester<decltype(vec2), UseSpecial::Yes> tester2(std::move(vec2));
    
    // std::vector vec2{1, 2, 3};
    // Tester<true> tester2(std::move(vec2));

    std::cout << tester1.Call() << std::endl;
    std::cout << tester2.Call() << std::endl;

    return 0;
}

Is there a way to make the commented lines work? Two lines above them of course works, but the type of the container can always be deduced, so I don't want to force the user to write it every time explicitly.

I have tried to write a deduction guide, but the problem is that the useSpecial parameter can't be deduced from the constructor. Or, maybe, I need to somehow redesign the whole thing?

In real code, Usual and Special have lots of methods, and these methods are used identically in Tester.


Solution

  • Class template argument deduction is all or nothing. You can't deduce Container if you supply useSpecial.

    You can write an alias for special Tester.

    template <typename Container>
    using SpecialTester = Tester<Container, UseSpecial::Yes>;
    
    std::vector vec2{1, 2, 3};
    SpecialTester tester2(std::move(vec2));