Here's my code:
#include <iostream>
#include <variant>
#include <vector>
class A {
public:
virtual void Foo() = 0;
};
class B : public A {
public:
void Foo() override {
std::cout << "B::Foo()" << std::endl;
}
};
class C :public A {
public:
void Foo() override {
std::cout << "C::Foo()" << std::endl;
}
};
template<typename... Args>
class D {
public:
template<typename T>
void Foo() {
m_variant = T{};
}
void Bar() {
std::get<m_variant.index()>(m_variant).Foo();
}
private:
std::variant<std::monostate, Args...> m_variant;
};
int main() {
D<B, C> d;
d.Foo<B>();
d.Bar();
d.Foo<C>();
d.Bar();
}
(c.f wandbox.org)
I'm getting the error no matching function for call to 'get' but I don't figure out why. std::variant::index() is constexpr, so it isn't the problem (I tested by putting directly the value 1, but still the same error).
I have a std::monostate to prevent an empty variant (when no args are in typename... Args)
m_variant.index() is a runtime value (as m_variant is not a constant expression).
The way to dispatch is to use visitor, as:
std::visit([](auto& v) { v.Foo(); }, m_variant);
Demo
Something marked constexpr tells you that in certain situations it can be called at compile time. It does not guarantee it can always be called at compile time.
I the case of variant, index can be called at compile time if the variant itself is a constexpr value. Otherwise it is a runtime method.
You can either read documentation about when something can be called at compile time, or reason about it; in this case, if the type of variant could vary at runtime, how can index be a compile time constant? Remember that only the ttpe and constexpr ness of values, plus if itself is in a compile time context, can be used to reason about "can this be called at compile time".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With