简体   繁体   中英

force a strongly typed enum to participate in template overload resolution

As per this question - template argument deduction with strongly-typed enumerations - it seems challenging - if not impossible - to get strongly typed enumerators to participate in overload resolution.

if we have the following

#include <string>
#include <iostream>

void ExternalFunction(const std::string& tag, int value)
{
    std::cout << tag << " - (int) " << value << std::endl;
}

void ExternalFunction(const std::string& tag, double value)
{
    std::cout << tag << " - (double) " << value << std::endl;
}

void ExternalFunction(const std::string& tag, const std::string& value)
{
    std::cout << tag << " - (string) " << value << std::endl;
}

class Wrapper
{
    public:
        virtual void DoSomething() = 0;
};

template <typename variable_type>
class VariableWrapper : public Wrapper
{
    public:
        VariableWrapper(variable_type variable) : variable(variable) {}
        
        void DoSomething() override
        {
            ExternalFunction("tag", variable);
        }
        
        variable_type& variable;        
};

template <typename enumerator, typename convert_to_string>
class EnumWrapper : public VariableWrapper<enumerator>
{
    public:

        EnumWrapper(enumerator& variable, convert_to_string encoder) : VariableWrapper<enumerator>(variable), encoder(encoder) {}

        void DoSomething() override
        {
            ExternalFunction("tag", encoder(VariableWrapper<enumerator>::variable));
        }
        
        convert_to_string encoder;
};

enum class StronglyTyped
{
    A,
    B,
    C
};

int main()
{
    StronglyTyped e = StronglyTyped::A;
    Wrapper* wrapper = new EnumWrapper(e, [](StronglyTyped S)->std::string{return "Test";});
    wrapper->DoSomething();
}

if we try to run this - http://coliru.stacked-crooked.com/a/d555c4e3300ab05d - we get the errors

main.cpp: In instantiation of 'void VariableWrapper<variable_type>::DoSomething() [with variable_type = StronglyTyped]':
main.cpp:31:14:   required from here
main.cpp:33:29: error: no matching function for call to 'ExternalFunction(const char [4], StronglyTyped&)'
   33 |             ExternalFunction("tag", variable);
      |             ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~
main.cpp:4:6: note: candidate: 'void ExternalFunction(const string&, int)'
    4 | void ExternalFunction(const std::string& tag, int value)
      |      ^~~~~~~~~~~~~~~~
main.cpp:4:51: note:   no known conversion for argument 2 from 'StronglyTyped' to 'int'
    4 | void ExternalFunction(const std::string& tag, int value)
      |                                               ~~~~^~~~~
main.cpp:9:6: note: candidate: 'void ExternalFunction(const string&, double)'
    9 | void ExternalFunction(const std::string& tag, double value)
      |      ^~~~~~~~~~~~~~~~
main.cpp:9:54: note:   no known conversion for argument 2 from 'StronglyTyped' to 'double'
    9 | void ExternalFunction(const std::string& tag, double value)
      |                                               ~~~~~~~^~~~~
main.cpp:14:6: note: candidate: 'void ExternalFunction(const string&, const string&)'
   14 | void ExternalFunction(const std::string& tag, const std::string& value)
      |      ^~~~~~~~~~~~~~~~
main.cpp:14:66: note:   no known conversion for argument 2 from 'StronglyTyped' to 'const string&' {aka 'const std::__cxx11::basic_string<char>&'}
   14 | void ExternalFunction(const std::string& tag, const std::string& value)
      |                                               ~~~~~~~~~~~~~~~~~~~^~~~~

Is it possible to get the strongly typed enumerator to participate in the overload resolution? I don't want to remove the strongly typing - which does remove this issue - as i will then have to use unique names between multiple enums

EDIT: i have removed the std::to_string from the question and updated the code accordingly as it was incorrectly being focused on.

You have written your code incorrectly.

OK, so EnumWrapper<>::DoSomething overrides VariableWrapper<T>::DoSomething . So it won't be called by directly calling DoSomething on any EnumWrapper object.

But that doesn't mean VariableWrapper<T>::DoSomething doesn't exist . It does exist, and you can still call it by a qualified call. As such, when you instantiate VariableWrapper<T> for some particular T , the member functions of this template class must be valid.

And VariableWrapper<T>::DoSomething is not valid for any T which cannot be used to call ExternalFunction directly. This has nothing to do with enumerations specifically; it's purely about how you wrote your function.

You should instead make EnumWrapper not inherit from VariableWrapper . They both can inherit from BaseWrapper , but they have no business inheriting from one another. Alternatively you could make ExternalFunction itself a template that can resolve how to do whatever it is that it does for any given type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM