How can I save a pointer to a function without save its return type?
For example:
int GetInt() { return 5; }
string GetStr() { return "abc"; }
FunctionPointerClass GetAny;
int main()
{
GetAny = &GetInt;
auto var = GetAny();
GetAny = &GetStr;
auto var2 = GetAny();
cout << var << '\n' << var2;
}
Edit
A simple way to do this is use variant<> (thanks #sehe), like this:
#include <boost/variant.hpp>
#include <string>
#include <iostream>
#include <functional>
int GetInt() { return 5; }
std::string GetStr() { return "abc"; }
int main()
{
std::function<boost::variant<int, std::string>()> Get;
Get = &GetInt;
std::cout << Get() << '\n';
Get = &GetStr;
std::cout << Get() << '\n';
}
But, it not too applicable for my project: a non-typed class. To use it, I will need stack all the used return types, to put it in template of variant<>. Like this:
class Var {
private:
void* _val;
template <typename T>
T& _Get() const {
return *((T*)_val);
}
// Static stack variable HERE
public:
val() {}
template <typename T>
val(T val) {
Set(val);
}
~val() {
if(_val != nullptr) delete _val;
}
std::function<boost::variant</*Stack*/>()> Get;
template <typename T>
void Set(T val) {
if(_val != nullptr) delete _val;
_val = new T(val);
Get = &_Get<T>;
// TODO Add 'T' to Stack
}
};
How can I do this?
Not exactly.
You can of course make it a function to print the value.
Or you can use std::variant/boost::variant to return either type.
Other techniques, like Type Erasure might also apply.
I flesh the last two of the approaches here:
Using variant<>
Live On Coliru
#include <boost/variant.hpp>
#include <string>
#include <iostream>
#include <functional>
int GetInt() { return 5; }
std::string GetStr() { return "abc"; }
int main()
{
std::function<boost::variant<int, std::string>()> Get;
Get = &GetInt;
std::cout << Get() << '\n';
Get = &GetStr;
std::cout << Get() << '\n';
}
Prints
5
abc
Using type erasure
A related technique is type erasure, where you define a "concept" with supported operations (in this case, output streaming) and you hide it behind a polymorphic interface. E.g:
struct Printable {
template <typename T> Printable(T v) : _stored(new concrete<T>(v)) { }
friend std::ostream& operator<<(std::ostream& os, Printable const& p) {
return p._stored->print(os);
}
private:
struct interface {
virtual std::ostream& print(std::ostream& os) const = 0;
virtual ~interface() = default;
};
template <typename T>
struct concrete : interface {
concrete(T v) : v(v) {}
virtual std::ostream& print(std::ostream& os) const override {
return os << v;
}
T v;
};
std::unique_ptr<interface> _stored;
};
In that case you can make the whole program:
Live On Coliru
int GetInt() { return 5; }
std::string GetStr() { return "abc"; }
int main()
{
std::function<Printable()> Get;
Get = &GetInt;
std::cout << Get() << '\n';
Get = &GetStr;
std::cout << Get() << '\n';
}
I was going to write this as a comment, and it's not REALLY an answer, but it's a lengthy discussion on the subject of "return different types from the a function with the same name".
C++ doesn't take return type into concideration for overloading functions. In other words, std::string GetAny() and int GetAny() are considered as duplicates of the same function, because they only differ in return type. That's a restriction in the language definition, and you have to work around this restriction by "doing something other than return two different types".
As discussed in another answer, one solution is boost::variant, which is basically a way to define a class that can have multiple different types inside it, which has a type of "tag" to determine what it really contains, and various other clever stuff related to that. Makes it very neat in many ways.
However, it is only really useful for certain classes of problems. In many cases, your code still needs to understand what the data-type is, and having a function that may return a string, an integer or any other "random" data type isn't meaningful. Yes, it's handy to be able to define function pointers that return "any" type - but only in so far as you can have a table of the functions. Your code will not really work well if you do:
std::string s;
s += GetAny(); // Happens to be returning `int` in this call.
Just as bad:
int x = GetAny(); // Returning a string...
So, whilst you can write code that may return "any type", it's hard to make use of such a function without knowing what it returns. I've been programming professionally for over 30 years, and I have used function pointers for many things. So far, I've managed to not need to use this more than a handful times, and every time, it's been some form of solution similar to boost::variant (essentially returning a data-structure, where one field is describing the data-type itself). The two cases I can think of where I have used this are in my Lisp interpreter and my Basic intrepreter. They need a "variable type" that have the ability to hold various types of objects (integer, float, string, list [only in Lisp]). In my Pascal compiler, I do have a proper type system, so it doesn't need to have multiple types returned from a single function (or function pointer). I'd say "it smells funny" when this type of situation happens, and you should probably think about what it is you're trying to solve, and if this is really the right solution.
Related
My solution I gonna use to add “C++ Extension Methods” to JNI jobjects to make NDK code more readable like (Uniform Function Call Syntax) is:
Subclass the class that I want to add extension methods.
For invoking the “Extension Methods” make a pointer of type ExtensionsClass to point to OriginalClass - (Although the pointed object is’nt an ExtensionsClass).
The overload is minimal & we can access public methods of the Original class.
#include <iostream>
// Represents a class external to my source
class Person {
public:
Person(){
privateage = 20;
}
int age() { return privateage; }
private:
int privateage;
short anotherField;
};
class PersonExtensions : private Person {
public:
inline int size() { return 5 + age(); }
//NoFieldsOnExtensionClass
};
int main() {
Person person;
PersonExtensions* pE = (PersonExtensions*) &person;
std::cout << pE -> size() << std::endl;
std::cout << (*pE).size() << std::endl;
std::cout << sizeof(Person) << std::endl;
std::cout << sizeof(PersonExtensions) << std::endl;
return 0;
}
Do you think that this incorrect pointer assignment, since “Extension Method” only accessed public members of extended class & extension class don’t going to have any Field variables, can represent a problem in the future?
The size of the object are the same.
Thanks a lot.
This is undefined behaviour.
Yes that can break at any point.
Consider overloading ->* or something instead.
Or just using a free function.
If you really want infix notation:
template<class T, class F>
struct extension_method_t {
F f;
friend auto operator->*( T& t, extension_method_t const& self ) {
return [&t,&self](auto&&...args)->decltype(auto) {
return self.f( t, decltype(args)(args)... );
};
}
};
template< class T, class F >
extension_method_t<T,F> extension_method( F f ) {
return {std::move(f)};
}
then:
auto size = extension_method<Person>([](auto& person)->int{
return 5+person.age();
});
Person p;
std::cout << (p->*size)() << "\n"; // prints p.age()+5
here we don't have an extension method, but we do have an extension method pointer.
What you are doing in your question code is Undefined Behavior, so an especially an optimizing compiler might do really "fun" things with it. In other words, don't do it, it might break at any time even if it works when you test it. Only way to make sure it would actually work would be to examine the produced assembly code after each compilation to make sure it does what you want, and this is essentially impossible, so it is never safe.
You are using private inheritance. So for same effect you can just do this:
class PersonExtensions {
public:
PersonExtensions(Person *person) : _person(person) {}
inline int size() { return 5 + _person->age(); }
private:
Person *_person;
};
If you instead used public inheritance (so you could just call Person methods through PersonExtensions), then you'd need to add a getter for _person (for cases where real Person is needed), and/or add delegates for Person methods (for so called static polymorphism).
The problem I tried to tackle today is the one where you want to return a reference, but you actually can't because in some specific case you return something 'empty'. Just to clarify, something like this:
std::array<std::string, 5> cStrings /* do something to init */
const std::string& get_my_string(/* args */) {
if(i_know_what_to_return()) {
/*
* returning happily something in
* cStrings if I know what
*/
} else {
/* oeps... i need to return something, I don't have :-( */
return std::string(); // DON'T TRY THIS AT HOME!
}
}
I was wondering if there is not a generic approach to avoid the creation of empty objects all over the place, or, even worse, start returning copies of the objects. So I was wondering if I could not create some sort of template class that allows me to tell the compiler to manage this for me. This was my approach (although its only one of many, all with a small variation in the template declaration since this produces an error)
template<typename T, decltype(T) V>
struct empty_reference {
using type = T;
static const T static_object_;
operator T&() const {
return static_object_;
}
};
template<typename T, decltype(T) V>
const typename empty_reference<T, V>::type
empty_reference<T, V>::static_object_ = V;
unfortunately, this does not work (I get an error on 'decltype(T) V' saying 'decltype expects an expression not a type'), but I guess this is mainly because I am missing something in the template declaration.
In the end I am hoping to use this class by returning
return empty_reference<std::string, std::string()>();
So I have three questions here;
could this be possible
how do I make this work, what should I turn 'decltype(T) V' into to tell the compiler that V should be of type T while still being evaluated during compilation?
and is this a good approach or is there an easier/better solution to this problem?
Not exactly the same, but you can get your string as a function parameter instead of as a return value and rely on the fact that temporaries bind to const references.
As an example:
#include <string>
#include <iostream>
#include <utility>
struct S {
template<typename F>
void get(bool b, F &&f) {
std::forward<F>(f)(b ? s : "");
}
std::string s{"foo"};
};
int main() {
S s;
s.get(true, [](const auto &str) { std::cout << str << std::endl; });
s.get(false, [](const auto &str) { std::cout << str << std::endl; });
}
This can be a valid alternative if libraries like Boost are not already part of your project and you don't want to include them.
Otherwise, as others have mentioned, you can pick up an upcoming utility called std::optional and combine it with std::reference_wrapper as it follows:
#include <string>
#include <iostream>
#include <experimental/optional>
#include <functional>
struct S {
std::experimental::optional<std::reference_wrapper<std::string>> get(bool b) {
return b ? std::ref(s) : std::experimental::optional<std::reference_wrapper<std::string>>{};
}
std::string s{"foo"};
};
int main() {
S s;
auto opt1 = s.get(true);
std::cout << (opt1 ? opt1->get() : "-") << std::endl;
auto opt2 = s.get(false);
std::cout << (opt2 ? opt2->get() : "-") << std::endl;
}
Pretty ugly indeed. Note that a std::optional should be verified through its operator bool or the member method has_value to be sure that it contains a value.
Unfortunately you cannot use directly a std::reference_wrapper as return value, for it cannot be (let me say) _empty). In other terms, if you want to construct such an object, you must pass a valid reference to its constructor.
Another approach would be by using a template class like the following one:
#include <string>
#include <type_traits>
#include <iostream>
template<typename T>
struct defval {
static const std::decay_t<T> value;
};
template<typename T>
const std::decay_t<T> defval<T>::value = T{};
struct S {
const std::string & get(bool b) {
return b ? str : defval<std::string>::value;
}
std::string str{"foo"};
};
int main() {
S s;
std::cout << s.get(true) << std::endl;
std::cout << s.get(false) << std::endl;
}
Note that you must specialize it for those types that are not default constructible.
References must be bound to an object. So you can't return a reference in your case. Your options are:
Return a (non-owning) pointer.
Return something like boost::optional, which can hold a reference (unlike the soon to be added std::optional).
So at some point I figured it out, at least I guess.
template<typename T>
struct empty_reference {
using type = T;
static const type static_object_;
operator const type&() {
return static_object_;
}
};
template<typename T>
const typename empty_reference<T>::type
empty_reference<T>::static_object_ = {};
The concept is that the compiler will 'generate' one static 'static_object_' member for all types you use it for. Therefore, for any type you used the empty_reference for, a static object is generated in your application and returned when they are requested (i.e. if you return empty_reference<int> in two different files, a reference to the same int value will be returned).
The key was to remove the 'decltype(T) V' completely and use the universal initialization (i.e. {}) to make sure that any 'empty' constructor is called to initialize the object.
The downside is the reference needs to be constant (otherwise you can edit your 'empty reference') and the type is required to be constructable using an empty constructor.
So I guess the only question remaining is whether it is a good idea (I am not going to just my own ideas). Happy to receive any other suggestions/feedback :-)
So with the new auto return type deductions in C++14, is there a way to create functions that have varying return types?
For example:
auto replaceStr(string base, string search, string replace) {
size_t found = base.find(search);
if (found == string::npos) {
return false; //Return this is replace is not found
}
else {
base.replace(found, (found+search.length()), replace);
return base; //Return this after the replacement
}
}
This doesn't work, I know. So is there a way to get it to work?
EDIT: Most people in the comments have been telling me this impossible since the compiler doesn't know what return type the function is at compilation. So perhaps we can have the function have a default return type with optional return types?
C++ is a statically typed language: There is no way to return a variable type that is not known during compile time.
See this SO question about statically- and dynamically-typed language differences, which are also known as weak or strong typing.
About C++14 auto return type, see When should I use C++14 automatic return type deduction?
As has been pointed out, the compiler needs to know the function return type at compile time.
For your particular example you could return a std::pair<bool, string>. In the case where no substitution is made, the second member of the pair is ignored.
auto res = replaceStr(base, search, replace);
if (res.first) {
auto newBase = res.second;
// ...
}
Although this doesn't answer your question directly, a common way to do this would be to pass a reference:
bool replaceStr(string &base, string search, string replace) {
size_t found = base.find(search);
if (found == string::npos) {
return false; //Return this is replace is not found
}
base.replace(found, (found+search.length()), replace);
return true;
}
You would then use it like:
if (replaceStr(base,search,replace)) {
// it was replaced, use the modified base.
}
else {
// it wasn't replaced
}
Most people in the comments have been telling me this impossible since
the compiler doesn't know what return type the function is at
compilation.
The compiler does know the type. If the compiler is unable to deduce the type, the program is ill-formed and won't compile. auto doesn't mean weakly-typed, it represents a placeholder type which can be deduced using template argument deduction.
C++ doesn't directly support variable return types but it's certainly possible to implement. Here's an example of variable return types with the return type selected at compile time in one case and at runtime in the other case.
#include <string>
#include <memory>
#include <sstream>
#include <iostream>
// dynamically varying return type
class AnyBase
{
public:
virtual ~AnyBase() {};
const std::string as_string() const
{
return this->as_string_v();
}
private:
virtual const std::string as_string_v() const = 0;
};
typedef AnyBase Any;
template<typename T>
class AnyDerived : public AnyBase
{
T* obj_ptr_;
public:
template<typename... Args>
AnyDerived(Args&&... args)
{
obj_ptr_ = new T(std::forward<Args...>(args...));
}
~AnyDerived()
{
delete obj_ptr_;
}
private:
const std::string as_string_v() const;
const char* type_string_v() const;
};
template<class T>
const std::string AnyDerived<T>::as_string_v() const
{
std::ostringstream oss;
oss << *obj_ptr_;
return oss.str();
}
std::ostream& operator<<(std::ostream& os, const Any& a)
{
os << a.as_string();
return os;
}
std::unique_ptr<Any> foo(bool as_char)
{
if (as_char)
return std::unique_ptr<Any>{new AnyDerived<char>('1')};
else
return std::unique_ptr<Any>{new AnyDerived<int>(1)};
}
// statically varying return type
template<typename T>
T bar()
{
return 1;
}
template<>
char bar<char>()
{
return '1';
}
int main()
{
bool as_char;
as_char = true;
const auto a1 = foo(as_char);
as_char = false;
const auto a2 = foo(as_char);
const auto a3 = bar<int>();
const auto a4 = bar<char>();
std::cout << "*a1: " << *a1 << std::endl;
std::cout << "*a2: " << *a2 << std::endl;
std::cout << " a3: " << a3 << std::endl;
std::cout << " a4: " << a4 << std::endl;
}
a1 wraps a pointer to char, a2 wraps a pointer to int, a3 is an int and a4 is a char. As you can see in main(), it can be made fairly transparent.
output:
*a1: 1
*a2: 1
a3: 1
a4: 1
In this case I'd just throw on error.
string replaceStr(string base, string search, string replace) {
size_t found = base.find(search);
if (found == string::npos) {
throw MyException();
}
else {
base.replace(found, (found+search.length()), replace);
return base; //Return this after the replacement
}
}
But if you want to create a factory-like function that returns anything you can:
use polymorphism and return a pointer to the base
cast anything you want to std::shared_ptr<void>.
use boost::any
Your function can return void*, which can point to anything. This approach, however, may get you in trouble with managing memory if you are not careful.
Consider the following class structure:-
class foo {
public:
int fun () {
cout << "in foo" << endl;
}
};
class bar_class1:public foo {
public:
int fun () {
cout << "in bar_class1" << endl;
}
};
class bar_class2:public foo {
public:
float fun () {
cout << "in bar_class2" << endl;
}
};
main () {
foo * foo_pointer = new bar_class1();
foo_pointer->fun();
}
The output of the above program is in foo. Is there a way, that using a pointer of type foo * which actually points to an object of type bar_class1 or bar_class2, we can call the fun function of the derived class instead of the base class? I am not able to make the fun function virtual in the base class foo since, then there is a return type conflict for function foo in the derived class bar_class2.
Here's my comments as an answer.
You cannot do that.
If that kind of polymorphism were possible, wouldn't that break horribly when code calls foo::fun (expecting an int) on an object whose actual type is bar_class2 and thus gets a float? Do you want to simply throw away type safety?
If you want different return types, sounds like you want a template. But you cannot use templates quite in the way that you want to use foo(). Static polymorphism (templates) and run time polymorphism (late binding) don't mix well. You need to redesign your oop structure.
If you absolutely hate type safety, you can sort of do this with void pointers. But for the love of Flying Spaghetti Monster, don't ever do this in c++. Please close your eyes before reading the following code to avoid exposure.
#include <iostream>
class foo {
public:
virtual void* fun() = 0;
virtual ~foo(){};
};
class bar_class1: public foo {
public:
void* fun() {
return &value;
}
private:
int value = 1;
};
class bar_class2: public foo {
public:
void* fun() {
return &value;
}
private:
float value = 1.1;
};
int main() {
foo* foo_pointer1 = new bar_class1();
foo* foo_pointer2 = new bar_class2();
// in c++ compiler must know the type of all objects during compilation
std::cout << *reinterpret_cast<int*>(foo_pointer1->fun()) << '\n';
std::cout << *reinterpret_cast<float*>(foo_pointer2->fun()) << '\n';
delete foo_pointer1;
delete foo_pointer2;
}
Perhaps similar to the existing answer, I really hope you realize changing your design is better than this mess, but I believe it's the best you're going to get. I force you to specify the return type at the callsite (e.g., someFoo->fun<int>()), since you're going to have to know it anyway, and dispatch based on that. Any funny business and you'll get an exception. Also keep in mind the performance of this is, I imagine, less than desirable.
#include <cassert>
#include <stdexcept>
#include <type_traits>
struct foo {
virtual ~foo() = default;
template<typename T, typename = typename std::enable_if<std::is_same<T, int>::value>::type, typename = void>
T fun();
template<typename T, typename = typename std::enable_if<std::is_same<T, float>::value>::type>
T fun();
};
struct bar_class1 : foo {
int fun() {
return 2;
}
};
struct bar_class2 : foo {
float fun() {
return 3.5f;
}
};
template<typename T, typename, typename Dummy>
T foo::fun() {
if (auto *p = dynamic_cast<bar_class1 *>(this)) {
return p->fun();
} else if (dynamic_cast<bar_class2 *>(this)) {
throw std::invalid_argument("Mismatching dynamic type.");
} else {
return 1;
}
}
template<typename T, typename>
T foo::fun() {
auto *p = dynamic_cast<bar_class2 *>(this);
if (dynamic_cast<bar_class1 *>(this) || !p) {
throw std::invalid_argument("Mismatching dynamic type.");
} else if (auto *p = dynamic_cast<bar_class2 *>(this)) {
return p->fun();
}
assert(false); //should never get here, but compiler doesn't know that
}
If you'd like the main function, I've written a complete sample.
To answer your question: No, late binding isn't possible without deciding the return type. ...at least not in a reasonable manner, see user2079303's great counter-example. But...
you may change your code (for example) into something like the following, using the keyword virtual and equalize the return type for instance to void:
class foo
{
public:
virtual void fun(std::ostream& out) {
out << "in foo" << std::endl;
}
};
so you can decide the output type later:
class intFoo: public foo
{
public:
void fun(std::ostream& out) {
// output an int
out << "in bar_class1. data: " << data << endl;
}
int data;
};
class floatFoo: public foo
{
public:
void fun(std::ostream& out) {
// output a float
out << "in bar_class2. data: " << data << endl;
}
float data;
};
For brevity, I double-use the output stream - now a parameter of the function fun() - function to demonstrate type-dependent portion of your derived class. In your application, the parameter will probably be of another, more useful type.
The function fun is not a virtual function since you didn't use the keyword "virtual" to decorate it. So, the compile will determine which function to call at compiling time. So, there is no way to tell the compiler to call another function because the compiler will use its static type, i.e. the variable definition type -- foo *.
I was wondering if it is possible to change the return type of a function based on the type of variable it is being assigned to. Here's a quick example of what I mean.
I want to create a function that parses a variable of int, bool, or float from a string. For example...
Int value = parse("37");
Float value = parse("3.14");
Bool value = parse("true");
I understand if I make this function a template, that the variable type must be determined from the argument list which is always going to be a string. Is there any other way of doing this with c++?
This can be done with a conversion function
struct proxy {
string str;
proxy(string const &str):str(str) { }
template<typename T> operator T() {
return boost::lexical_cast<T>(str);
}
};
proxy parse(string const &str) { return proxy(str); }
Now you just need to do
float a = parse("3.1");
And it should work well. Incidentally, you may just use the class directly. I recommend renaming it to conversion_proxy to point to the fact that it's just a proxy to a happening conversion but that it itself doesn't do conversion
struct conversion_proxy {
string str;
conversion_proxy(string const &str):str(str) { }
template<typename T> operator T() {
return boost::lexical_cast<T>(str);
}
};
float a = conversion_proxy("3.1");
I can't tell from your question if you know this or not, but you can indeed do this with a template. The only catch is that you will have to specify the type that you are converting from in each invocation instead of relying on inference (since as you said the argument type will always be the same).
template<typename T> T parse(const string& str) { /* do stuff for other types */ }
template<> int parse<int>(const string& str) { /* do stuff for ints */ }
template<> double parse<double>(const string& str) { /* do stuff for doubles */ }
template<> bool parse<bool>(const string& str) { /* do stuff for bools */ }
// etc.
And then invoke as
int value = parse<int>("37");
double value = parse<double>("3.14");
bool value = parse<bool>("true");
If you already knew this just ignore this answer, but it's not clear from your question that you are aware that this is possible.
Of course, if what you're doing isn't really generic (and so you have to specialize for each type you want to parse) then writing a template isn't the right thing to do anyway.
By the way, you can do it pretty generically with a single function like this (assuming parse is what you really want to do):
#include <sstream>
template<typename T> T parse(const string& str)
{
T t;
std::istringstream sstr(str);
sstr >> t;
return t;
}
This will work for any default-constructable, stream-extractable type, which includes all built-ins.
You could pass your output argument as a pointer or reference.
Like this:
template<class T> void parse(const std::string &input, T& output);
Then code like this:
double d; parse(input, d);
int i; parse(input, i);
should work.
However, your code looks like a perfect fit for an std::istringstream that would just be:
istringstream is(input);
input >> d;
If you have somewhat complicated formatting involved, a trick I have had pretty good luck with involves creating custom objects with custom operator>> that pulls out data.
Then it could be like:
istringstring is(input);
input >> LineExtracter(x, y, d);
I would agree with litb who was a little quicker than myself. Use the casting operators.
#include <iostream>
#include <string>
#include <sstream>
class Convertible
{
public:
int m_Integer;
bool m_Bool;
double m_Double;
Convertible() : m_Integer(0), m_Bool(false), m_Double(0.0) {};
operator int() const
{
return m_Integer;
}
operator bool() const
{
return m_Bool;
}
operator double() const
{
return m_Double;
}
};
Convertible parse(std::string data)
{
Convertible l_result;
std::istringstream converter(data);
converter >> l_result.m_Integer;
std::istringstream converter2(data);
converter2 >> l_result.m_Bool;
std::istringstream converter3(data);
converter3 >> l_result.m_Double;
return l_result;
}
void main()
{
int l_convertedInt = parse("2");
bool l_convertedBool = parse("true");
double l_convertedDouble = parse("3.14");
std::cout << "Converted '2' to " << l_convertedInt << std::endl;
std::cout << "Converted 'true' to " << l_convertedBool << std::endl;
std::cout << "Converted '3.14' to " << l_convertedDouble << std::endl;
}
Unfortunately, that isn't possible. In C++ it is not possible to overload a function based on it's return value. You either have to have 3 functions, ParseInt, ParseFloat, and ParseBool, or use a function template.
You could return void* and then cast the result as needed.
I advise against this though. C++ is a strongly typed language. The advantage of this is that the compiler can catch errors earlier than a dynamically typed language.
No this type of behavior is not possible in C++. To be allowable it would necessitate being able to define functions of the same name at the same scope that differed only by return type. This is not legal in C++.
C++ can do some return type specialization such as covariant return types on overridden virtual functions. But it does not support what you are looking for.
Here's my adaptation of #Tyler McHenry's answer for my situation where the argument to parse() is a type other than a string.
Note that I found I had to introduce a template specialization in order to avoid a type conversion warning (float to int).
(Also see live demo.)
#include <iostream>
struct MyUnion
{
public:
union {
bool bool_value;
int int_value;
float float_value;
};
};
template<typename T> T parse(const MyUnion& h)
{
T t;
if (typeid(T) == typeid(bool)) {
t = h.bool_value;
} else if (typeid(T) == typeid(int)) {
t = h.int_value;
} else if (typeid(T) == typeid(float)) {
// t = h.float_value; // see **Warning** below; use float specialization instead
}
return t;
}
// 'float' template specialization to avoid conversion warning.
template<> float parse(const MyUnion& h)
{
return h.float_value;
}
int main()
{
MyUnion mu1; mu1.bool_value = true;
MyUnion mu2; mu2.int_value = 42;
MyUnion mu3; mu3.float_value = 3.14159;
std::cout << "As bool: " << parse<bool>(mu1) << std::endl;
std::cout << "As int: " << parse<int>(mu2) << std::endl;
std::cout << "As float: " << parse<float>(mu3) << std::endl;
}
// **Warning**
// In function 'T parse(const Heterogeneous&) [with T = int]':
// Line 22: warning: converting to 'int' from 'const float'