0

I have a class, Property, that has two template parameters: the type of the property, and whether or not the property is optional (i.e. might not exist).

The code I've written to represent this logic looks like this:

#include<type_traits>
#include<optional>
#include<iostream>

template<typename Type, bool Optional>
struct Property {
    std::conditional_t<Optional, std::optional<Type>, Type> value;
    void do_thing() {
        if constexpr (Optional) {
            if(value)
                std::cout << *value << std::endl;
            else
                std::cout << "null" << std::endl;
        } else {
            std::cout << value << std::endl;
        }
    }
};

template<bool Optional>
void Property<std::string, Optional>::do_thing() {
    if constexpr (Optional) {
        if(value)
            std::cout << "\"" << *value << "\"" << std::endl;
        else
            std::cout << "null" << std::endl;
    } else {
        std::cout << "\"" << value << "\"" << std::endl;
    }
}

int main() {
    Property<int, false> prop1{11};
    prop1.do_thing();
    Property<int, true> prop2;
    prop2.do_thing();
    Property<std::string, false> prop3{"Test"};
    prop3.do_thing();
}

One of the things I need is I need do_thing() to change in behavior if the Type is std::string (or a number of other types I need to specialize).

But, when I try to compile this code, GCC complains about the specialization:

<source>:21:48: error: invalid use of incomplete type 'struct Property<std::__cxx11::basic_string<char>, Optional>'
   21 | void Property<std::string, Optional>::do_thing() {
      |                                                ^
<source>:6:8: note: declaration of 'struct Property<std::__cxx11::basic_string<char>, Optional>'
    6 | struct Property {
      |        ^~~~~~~~
Execution build compiler returned: 1

What is the proper way to implement this specialization of the function?

Xirema
  • 19,889
  • 4
  • 32
  • 68

1 Answers1

0

What is the proper way to implement this specialization of the function?

The correct way would be to first partially specialize the class template itself for the required template arguments as shown below:

//partially specialize the class first 
template<bool Optional>
struct Property<std::string, Optional>
{
    std::conditional_t<Optional, std::optional<std::string>, std::string> value;
    void do_thing();
};
//now write the implementation for the member function
template<bool Optional>
void Property<std::string, Optional>::do_thing() {
    if constexpr (Optional) {
        if(value)
            std::cout << "\"" << *value << "\"" << std::endl;
        else
            std::cout << "null" << std::endl;
    } else {
        std::cout << "\"" << value << "\"" << std::endl;
    }
}

Working Demo

Jason
  • 36,170
  • 5
  • 26
  • 60