I have the following code:
#include <boost/variant.hpp>
#include <iostream>
#include <string>
boost::variant<int, double, std::string> variant;
template <typename FirstArg, typename... OtherArgs>
auto bar(const std::type_info& variant_type_info) -> decltype(typeid(FirstArg) == variant_type_info ? boost::get<FirstArg>(variant) : bar<OtherArgs...>(variant_type_info))
{
if (typeid(FirstArg) == variant_type_info)
{
return boost::get<FirstArg>(variant);
}
return bar<OtherArgs...>(variant_type_info);
}
template <typename... VariantArgs>
auto foo(const boost::variant<VariantArgs...>& variant) -> decltype(bar<VariantArgs...>(variant.type()))
{
return bar<VariantArgs...>(variant.type());
}
int main()
{
variant = 0.5;
const auto& baz = foo(variant);
std::cout << baz << '\n';
}
It gives me the following errors:
main.cpp:9:135: error: 'bar' was not declared in this scope
auto bar(const std::type_info& variant_type_info) -> decltype(typeid(FirstArg) == variant_type_info ? boost::get<FirstArg>(variant) : bar<OtherArgs...>(variant_type_info))
^
main.cpp:9:148: error: expected primary-expression before '...' token
auto bar(const std::type_info& variant_type_info) -> decltype(typeid(FirstArg) == variant_type_info ? boost::get<FirstArg>(variant) : bar<OtherArgs...>(variant_type_info))
^
main.cpp:9:148: error: expected ')' before '...' token
main.cpp:9:135: error: 'bar' was not declared in this scope
auto bar(const std::type_info& variant_type_info) -> decltype(typeid(FirstArg) == variant_type_info ? boost::get<FirstArg>(variant) : bar<OtherArgs...>(variant_type_info))
^
main.cpp:9:54: error: expected type-specifier before 'decltype'
auto bar(const std::type_info& variant_type_info) -> decltype(typeid(FirstArg) == variant_type_info ? boost::get<FirstArg>(variant) : bar<OtherArgs...>(variant_type_info))
^
main.cpp:9:54: error: expected initializer before 'decltype'
main.cpp:20:69: error: 'bar' was not declared in this scope
auto foo(const boost::variant<VariantArgs...>& variant) -> decltype(bar<VariantArgs...>(variant.type()))
^
main.cpp:20:69: error: 'bar' was not declared in this scope
main.cpp:20:84: error: expected primary-expression before '...' token
auto foo(const boost::variant<VariantArgs...>& variant) -> decltype(bar<VariantArgs...>(variant.type()))
^
main.cpp:20:84: error: expected ')' before '...' token
main.cpp:20:69: error: 'bar' was not declared in this scope
auto foo(const boost::variant<VariantArgs...>& variant) -> decltype(bar<VariantArgs...>(variant.type()))
^
main.cpp:20:69: error: 'bar' was not declared in this scope
main.cpp:20:60: error: expected type-specifier before 'decltype'
auto foo(const boost::variant<VariantArgs...>& variant) -> decltype(bar<VariantArgs...>(variant.type()))
^
main.cpp:20:60: error: expected initializer before 'decltype'
main.cpp: In function 'int main()':
main.cpp:28:34: error: 'foo' was not declared in this scope
const auto& baz = foo(variant);
Coliru example - http://coliru.stacked-crooked.com/a/4467c33489b08359
I see that I can't refer to the same function in the decltype. Is there any workaround for such case? I am trying to write function to retrieve current value from boost::variant object.
Yes, there is a workaround in the general case. It's called:
Partial ordering. To get forward references as well, move methods into class namespace.
However
Nothing is gonna save you here. You cannot get hope to get the compiler to recover the static type of an argument, unless you already know it at compile time. This should be kinda obvious.
I mean, what should be the return type of foo()? How could it possibly contain all possible element types? Right. That's why you had the variant to begin with.
Three ways forward:
know the type statically:
const auto& baz = boost::get<double>(variant);
return the typeid instead:
std::type_info const& typeinfo_value = variant.type();
branch out and create separate paths to handle all cases. Boost has the static_visitor for this case:
struct Visitor : boost::static_visitor<std::string> {
std::string operator()(std::string const&) const { return "std::string"; }
std::string operator()(int) const { return "int"; }
std::string operator()(double) const { return "double"; }
template <typename... T>
std::string operator()(boost::variant<T...> const& v) const {
return boost::apply_visitor(*this, v);
}
};
int main()
{
static const Visitor _visitor;
variant = 0.5f;
std::cout << "The actual type is " << _visitor(variant) << "\n";
}
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