简体   繁体   中英

How to use a compile-time interface with a runtime type?

I have a function that takes a T and calls specific functions on the supplied object. Until now it was used from compile-time objects, so all was great. Minimal example:

#include <iostream>

struct A {
   void fun() const { std::cout << "A" << std::endl; }
};

struct B {
   void fun() const { std::cout << "B" << std::endl; }
};

template<class T>
void use_function(const T& param) {
   param.fun();
}

int main() {
   use_function(A{}); // "A"
   use_function(B{}); // "B"
   return 0;
}

Now I'm trying to use that use_function() with objects that get created at runtime and having a hard time. I can't use std::variant or std::any since I need to supply the type as template parameter for their access functions - although all their variants fulfil the function interface. Example for a (failing) variant approach:

using var_type = std::variant<A, B>;

struct IdentityVisitor {
   template<class T>
   auto operator()(const T& alternative) const -> T {
      return alternative;
   }
};

int main() {
   var_type var = A{};

   // error C2338: visit() requires the result of all potential invocations to have the same type and value category (N4828 [variant.visit]/2).
   use_function(std::visit(IdentityVisitor{}, var));
   return 0;
}

What is possible is directly calling the function with an appropriate type like this:

if (rand() % 2 == 0)
   use_function(A{});
else
   use_function(B{});

just storing it in between is what I can't get working.

I understand on a technical level but having trouble coming up with an elegant solution. Is there one? I know that I could rewrite the objects with even a lightweight inheritance - but was trying to see if it's feasible to avoid it altogether, even if just as an exercise to avoid OOP in favor of templates and concepts. I feel like variants should be working with this, but apparently not.

std::visit([](auto const& x) { use_function(x); }, var);

If overload sets were objects, you could pass use_function to std::visit directly. Because they aren't, you need to wrap it in something that will be instantiated as a call to the right overload.

std::visit([](auto const& x) { use_function(x); }, var);

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