Reputation: 165
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
)
Upvotes: 3
Views: 3442
Reputation: 217085
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);
Upvotes: 6
Reputation: 275230
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".
Upvotes: 1