Specialization of templated method in a templated class

134 Views Asked by At

I have a simple template class with a template method in it:

#include <iostream>
#include <optional>

template <typename T>
class Test
{
public:
    template <typename U>
    std::optional<U> test() { return std::nullopt; }

    std::optional<double> test() { return std::make_optional<double>(3.0); }
};

int main()
{
    Test<int> t;
    std::cout << t.test<int>().value_or(100) << " " << t.test<double>().value_or(100) << std::endl;
}

I'd like the program to print 100 3.0 or 100 3 rather than 100 100. How do I specialize the test method within Test such that it returns a non-empty optional with value 3.0?

In addition to the above, I've tried to add template<> above the specialization. This results in a compiler error (running gcc -std=c++17 test.cpp with GCC 9.4.0):

test.cpp:11:14: error: explicit specialization in non-namespace scope ‘class Test<T>’
   11 |     template<>
      |     
1

There are 1 best solutions below

5
On

You can specialize test for double in the following way:

#include <iostream>
#include <optional>

template <typename T>
class Test
{
public:
    template <typename U>
    std::optional<U> test() { return std::nullopt; }

    // Specialization for double:
    template <>
    std::optional<double> test() { return std::make_optional<double>(3.0); }
};

int main()
{
    Test<int> t;
    std::cout << t.test<int>().value_or(100) << " " << t.test<double>().value_or(100) << std::endl;
}

Output:

100 3

Update:
This solution works for MSVC, but not for GCC. See more info here, and here.
A possible workaround for GCC is to use if constexpr instead of a specialization:

template <typename T>
class Test
{
public:
    template <typename U>
    std::optional<U> test() 
    { 
        if constexpr (std::is_same_v<U, double>)
        {
            return std::make_optional<double>(3.0);
        }
        return std::nullopt; 
    }
};