I was working with boost::variant<int,std::string,bool> and its visitors when I runned into an unexpected behavior: the string and bool values were comparable. I don't know, why does it work like this, but I found it interesting. My only idea is that the variant with the bool value was interpreted as a char? Someone could explain it to me?
The comparsion visitor:
#include <iostream>
#include <algorithm>
#include <vector>
#include <boost/variant.hpp>
#include <boost/function.hpp>
struct my_less : boost::static_visitor<bool*>
{
template<typename T>
bool* operator()(T a, T b) const
{
return a<b ? new bool(true) : new bool(false);
}
template<typename T, typename U>
bool* operator()(T a, U b) const
{
return NULL;
}
};
int main()
{
typedef boost::variant<int,bool,std::string> datatype;
datatype *a = new datatype(false);
datatype *b = new datatype("abc");
my_less cmp;
bool* val = boost::apply_visitor(cmp,*a,*b);
if(val)
{
std::cout << *val;
}
else
{
std::cout << "NULL";
}
}
EDIT
Here is an extended main function with some test cases:
void show_result(bool* val)
{
if(val)
{
std::cout << *val << std::endl;
}
else
{
std::cout << "NULL" << std::endl;
}
}
int main()
{
//std::string a = "bbb";
//bool b = true;
//std::cout << b<a; //compilation error
typedef boost::variant<int,bool,std::string> datatype;
datatype int_value_1(4);
datatype int_value_2(3);
datatype string_value("abc");
datatype bool_value(true);
my_less cmp;
std::cout<<"First result, compare ints 4 and 3:"<<std::endl;
bool* val = boost::apply_visitor(cmp,int_value_1,int_value_2);
show_result(val);
std::cout<<"Second result, compare int to string 4 to abc " << std::endl;
val = boost::apply_visitor(cmp,int_value_1,string_value);
show_result(val);
std::cout <<"Third result, int 4 to bool true:" << std::endl;
val = boost::apply_visitor(cmp,int_value_1,bool_value);
show_result(val);
std::cout<<"Fourth result, string abc to bool true" << std::endl;
val = boost::apply_visitor(cmp,string_value,bool_value);
show_result(val);
}
The output:
First result, compare ints 4 and 3:
0
Second result, compare int to string 4 to abc
NULL
Third result, int 4 to bool true:
NULL
Fourth result, string abc to bool true
0
OK, now that you've completely changed your program, let me try again.
The problem is:
datatype *b = new datatype("abc");
"abc" is a const char*, not a std::string. If you want to create a std::string variant, you need to do so explicitly. Otherwise, you'll end up creating a bool variant because all pointers are convertible to bool, including const char* pointers.
Try this
datatype *b = new datatype(std::string("abc"));
This interaction between bool and std::string is apparently well-known and somewhat irritating. boost::variant provides a templated constructor, but the resolution rules prefer the built-in converstion to bool and there's no way in C++ to specify a template specialization on a constructor. It is possible to explicitly specialize assignment, so you can write:
datatype b;
b.operator=<std::string>("abc");
which might be marginally more efficient but much less readable than
datatype b;
b = std::string("abc");
If you don't include bool as a variant, then string literals do automatically convert to std::string. Maybe it's possible to use some sort of proxy pseudo-boolean class. I've never tried.
Related
Say I have a class / struct like below:
struct A {
uint32_t a;
uint8_t b;
uint16_t c;
};
And I have a set of strings that associate to each member of A (could be of different integer types, but not non-integer types such as strings), e.g.
"field1" -> A::a
"field2" -> A::b
"field3" -> A::c
Assume that there is always a 1:1 mapping between the strings and members. Is there an elegant way to map each string to each member using something like std::unordered_map?
I want to be able to read and write to each field using the strings as keys, e.g.
A a {1,2,3};
mymap["field1"] = 4; // a.a = 4
mymap["field2"] = 5; // a.b = 5
auto c = mymap["field3"]; // c = a.c = 3
I'm using C++11/14 and can't use boost.
Some more information on the context of this question:
The struct A mentioned in the question are settings of the program. They are hardware configuration parameters and my software program is used to simulate hardware behaviours. These settings/configurations are script-generated structs like above. We read / write these struct members and because the amount of these settings/configurations are so many (a few thousands), it would be convenient to be able to access them by their names as well. This is how & why I want to associate each member with a string. Whether it is subscripting or a function to access the corresponding members does not really matter, but there is such a 1:1 mapping between a string (name of the setting) and the generated struct member. And as I mentioned in the question, these members are of different integer types.
You could make a proxy-class that wraps around a integer, then store this proxy class in a std::unordered_map.
#include <iostream>
#include <functional>
#include <unordered_map>
struct A {
uint32_t a;
uint8_t b;
uint16_t c;
};
struct ValueWrapper {
using value_type = uint64_t;
template <typename Obj, typename T>
ValueWrapper(Obj& obj, T Obj::*member) {
get = [&, member]() { return obj.*member; };
set = [&, member](value_type value) mutable { obj.*member = value; };
}
ValueWrapper() = default;
ValueWrapper& operator=(value_type value) {
set(value);
return *this;
}
operator value_type() {
return get();
}
std::function<value_type()> get;
std::function<void(value_type)> set;
};
std::unordered_map<std::string, ValueWrapper> make_map(A& a) {
std::unordered_map<std::string, ValueWrapper> map;
map["field1"] = ValueWrapper(a, &A::a);
map["field2"] = ValueWrapper(a, &A::b);
map["field3"] = ValueWrapper(a, &A::c);
return map;
}
int main() {
A a{1,2,3};
auto map = make_map(a);
map["field2"] = 67;
std::cout << a.a << " " << static_cast<int>(a.b) << " " << a.c << std::endl;
std::cout << map["field1"] << " " << map["field2"] << " " << map["field3"] << std::endl;
}
You do get some restrictions depending on the value_type. If you use int64_t you could wrap anything but a uint64_t safely. If you go for a uint64_t you could wrap all the unsigned integers, but not the signed ones safely.
I put the default constructor there to satisfy unordered_maps use of operator[].
template<class V>
struct pseudo_ref_t {
operator V()&& { return getter(); }
void operator=(V v)&&{
setter(std::move(v));
}
std::function<void(V)> setter;
std::function<V()> getter;
};
template<class T, class V>
struct member_t {
friend pseudo_ref_t<V> operator->*( T* t, member_t const& self ) {
return {
[&self, t](V in){ self.setter(*t, std::move(in)); },
[&self, t]()->V{ return self.getter(*t); }
};
}
friend V operator->*( T const* t, member_t const& self ) {
return self.getter(*t);
}
std::function<void(T&, V)> setter;
std::function<V(T const&)> getter;
};
template<class T, class V, class X>
member_t<T, V> make_member( X T::* mem_ptr ) {
return {
[mem_ptr](T& t, V in) {
(t.*mem_ptr) = std::move(in);
},
[mem_ptr](T const& t)->V {
return (t.*mem_ptr);
}
};
}
a member_t<A, uint32_t> can type-erase any member of A that implicitly convertible to/from a uint32_t.
It acts like a smart member pointer.
you said that it could have different integer types, but it is a problem for having an elegant solution. If you can set up on a single type, this would be simple, like the following.
#include <iostream>
#include <map>
struct A {
int a;
int b;
int c;
};
using namespace std;
int main() {
map<string, int A::*> abc = {
{"a", &A::a},
{"b", &A::b},
{"c", &A::c}
};
A aa;
aa.*abc["a"] = 1;
aa.*abc["b"] = 2;
aa.*abc["c"] = 3;
cout << "a = " << aa.a << "(" << aa.*abc["a"] << ")" << endl;
cout << "b = " << aa.b << "(" << aa.*abc["b"] << ")" << endl;
cout << "c = " << aa.c << "(" << aa.*abc["c"] << ")" << endl;
return 0;
}
The main challenge of your question is that different members have different types.
If you make the types the same, you can use a lot of tricks.
For your case, I know you don't want to use Boost or C++17, but just to show you the challenges ahead, let me give you a Boost.Hana, C++17 solution.
#define BOOST_HANA_CONFIG_ENABLE_STRING_UDL
#include <boost/hana/equal.hpp>
#include <boost/hana/string.hpp>
#include <cstdint> // uint
#include <cassert>
struct A {
uint32_t a;
uint8_t b;
uint16_t c;
};
struct map{
A& aa_;
template<class String>
decltype(auto) operator[](String s) const{
using namespace boost::hana::literals;
if constexpr(s == "field1"_s) return (decltype(aa_.a)&)(aa_.a);
if constexpr(s == "field2"_s) return (decltype(aa_.b)&)(aa_.b);
if constexpr(s == "field3"_s) return (decltype(aa_.c)&)(aa_.c);
}
};
using namespace boost::hana::literals;
void f(uint32_t& a){ a = 3.;}
int main(){
A aa{1,2,3};
map mymap{aa};
mymap["field1"_s] = 4; assert(aa.a == 4);
mymap["field2"_s] = 5; assert(aa.b == 5);
mymap["field3"_s] = 6; assert(aa.c == 6);
auto c = mymap["field3"_s]; assert( c == aa.c );
mymap["blabla"_s]; // is void (not a compile error)
assert( map{aa}["field1"_s] == 4 );
}
From this you can walk backwards and perhaps figure out a C++14, the challenge ahead is that you have to implement your own compile time string literals and equality.
In other words, reimplement your own Hana string strings: https://www.boost.org/doc/libs/1_61_0/libs/hana/doc/html/namespaceboost_1_1hana_1_1literals.html
The simple solution is that if you have a script that can generate the struct then you can have your script generate your setters.
Start with a simple function interface.
struct A {
uint32_t a;
uint8_t b;
uint16_t c;
};
typedef std::function<void(A &,string)> SetterType
Then create a lookup table
std::map<std::string,SetterType> Lookup;
and for each field, using your script, generate a parser and setter;
void A_a(A & data, std::string input){
data.a = std::stoi(input);
}
and then
Lookup["a"] = &A_a;
and use it like
Lookup["a"]("10");
If you can't modify the generating script then maybe you can use a third party parser such as swig or clang to read your structures and generate you a parse tree that you can then use to generate your lookup tables.
Or just use a system that already maps strings to C++. A C++ JSON generator.
https://nlohmann.github.io/json/
I'm hoping there's a way to write a single get function for a class with a large number of accessible (but non-editable) data members, of mixed type. Use of a map holding void*-cast copies of the members' addresses will work, as seen in the following code, but as soon as a 'const' is thrown in to the mix to enforce read-only, unsurprisingly C++ barks saying that 'const void*' type cannot be recast in order to appropriately access the data member. The following code works for writing a single get function for a class of mixed data types, but it effectively makes all data members accessed by the get function public (see specifically the get function in the memlist class).
Bottom line:
Is there a way to make a pointer type-castable while retaining read-only at the actual memory location? Or more fundamentally, can one define a type cast-able pointer to a constant variable? E.g., it seems to me that const type *var defines a read-only/non-castable address to a read-only variable, whereas I am trying to find something (that hasn't worked for me as of yet) more like type * const var, though I haven't been able to find any documentation on this.
#include <iostream>
#include <string>
#include <map>
class A{
public:
A(int a, double b): a(a), b(b) {};
private:
int a;
double b;
friend std::ostream& operator<<(std::ostream& os, A& rhs);
};
class memlist{
public:
memlist(int param1, double param2)
{
myint = new int(param1);
mydouble = new double(param2);
myclass = new A(param1,param2);
getMap["myint"] = myint;
getMap["mydouble"] = mydouble;
getMap["myclass"] = myclass;
}
~memlist()
{
delete myint;
delete mydouble;
delete myclass;
}
void* get(std::string param) {return getMap[param];};
private:
int *myint;
double *mydouble;
A *myclass;
std::map<std::string,void*> getMap;
};
std::ostream& operator<<(std::ostream& os, A& rhs){
os << rhs.a << std::endl << rhs.b;
return os;
};
int main(){
int myint = 5;
double mydbl = 3.14159263;
memlist mymem(myint,mydbl);
std::cout << *(int*)mymem.get("myint") << std::endl;
std::cout << *(double*)mymem.get("mydouble") << std::endl;
std::cout << *(A*)mymem.get("myclass") << std::endl;
*(int*)mymem.get("myint") = 10;
std::cout << *(int*)mymem.get("myint") << std::endl;
return 0;
}
Output:
5
3.14159
5
3.14159
10
The code shown is very, shall we say, ill-designed.
void* is as close to destroying the type system as it gets in C++. As mentioned in the comments, std::any is a better solution to this.
That said, I took it as a challenge to implement what you have illustrated in the question in a type-safe manner. It was overkill, to say the least.
#include <iostream>
#include <type_traits>
using namespace std;
template<typename>
struct is_str_literal : false_type {};
template<size_t N>
struct is_str_literal<const char[N]> : true_type {};
template<typename T>
struct is_str_literal<T&> : is_str_literal<T> {};
template<typename T>
constexpr bool is_str_literal_v = is_str_literal<T>::value;
constexpr bool samestr(const char* arr1, const char* arr2, size_t n)
{
return n == 0 ? arr1[0] == arr2[0] :
(arr1[n] == arr2[n]) && samestr(arr1, arr2, n - 1);
}
template<size_t N1, size_t N2>
constexpr bool samestr(const char (&arr1)[N1], const char (&arr2)[N2])
{
return N1 == N2 ? samestr(arr1, arr2, N1 - 1) : false;
}
constexpr char myint[] = "myint";
constexpr char mydouble[] = "mydouble";
constexpr char myclass[] = "myclass";
struct S
{
template<const auto& name>
const auto& get()
{
static_assert(is_str_literal_v<decltype(name)>, "usage: get<var name>()");
if constexpr(samestr(name, ::myint))
return myint;
if constexpr(samestr(name, ::mydouble))
return mydouble;
if constexpr(samestr(name, ::myclass))
return myclass;
}
int myint;
double mydouble;
char myclass;
};
int main()
{
S s;
s.myint = 42;
s.mydouble = 10.0;
s.myclass = 'c';
cout << s.get<myint>() << endl;
cout << s.get<mydouble>() << endl;
cout << s.get<myclass>() << endl;
}
Live
This uses C++17.
After some further poking around, I have to respectfully disagree with the previous assessments in the comments and answers... I have, since posting this question, come across many functions in the standard C library where void * types are readily used (http://www.cplusplus.com/reference/cstdlib/qsort/), not to mention it being the return type of malloc (probably the most widely-used function in C/C++?) which relies on programmer type-casting. Also, to the best of my knowledge, std::any is a new c++17 class, so how might you have answered this question 6 months ago?
I'm attempting to write a template function that will return different types based on a string that is passed in.
template<typename T>
T test(string type)
{
int integer = 42;
float floateger = 42.42;
if (type == "int")
return integer;
if (type == "float")
return floateger;
}
int main()
{
int integer = test("int");
cout << "INTEGER: " << integer << endl;
}
When I run this I get the following error:
error: no matching function for call to 'test(const char [4])
How can I implement such a thing?
My end goal is to write a function that will return objects of different classes depending on what string is passed into it. I know this probably isn't the right approach at all. What is the correct way to do something like this?
A function always returns a value of the same type.
What you can do is to return a pointer to a common base class:
struct A {};
struct B : A {};
struct C : A {};
A* make(const std::string& s)
{
if (s == "B")
return new B;
else if (s == "C")
return new C;
else
return nullptr;
}
You can't do that, at least not that way.
In order to be able to return different types you would have to first return by reference and second the possible returned types would have to inherit from the declared return type.
For example:
class Base {
};
class Derived1 : public Base {
};
class Derived2 : public Base {
};
Base& func(string type) {
static Derived1 d1;
static Derived2 d2;
if( type == "Derived1" )
return d1;
if( type == "Derived2" )
return d2;
//etc
}
I'd do something like this. Instead of returning the value, make it a second parameter:
template<class T>
void test(const char *var_type, T& ret) {
int integer = 42;
float f = 42.42;
if (0 == strcmp(var_type, "int")) {
ret = integer;
} else if (0 == strcmp(var_type, "float")) {
ret = f;
}
}
Then you can call it like this:
int integer = 0;
float f = 0.0;
test((const char *) "int", integer);
printf("%d\n", integer);
test((const char *) "float", f);
printf("%f\n", f);
With Boost you could solve this by using boost::variant:
typedef boost::variant< int, float, YourSpecialDataType > MixedData;
And then have the method return this type:
MixedData test(std::string type) {
int integer = 42;
float floateger = 42.42;
if (type == "int")
return integer;
if (type == "float")
return floateger;
}
It's not possible in general to overload the returned value, for it would be impossible for the compiler to solve it. Imagine a statement like the following one:
your_overloaded_function();
You don't store the returned value in any variable, for you are not interested in it, so how could the compiler understand which function you want to invoke? It cannot, simply.
You can return a base class of a hierarchy, that is not an overloaded returned value indeed, but it let you to return different instances of different classes, thus getting something near to what you're trying to achieve.
Anyway, there are some tricks to get it explicitly. It follows a possible one using partial specialization:
#include <iostream>
#include <type_traits>
using namespace std;
template<typename T, typename Enable = void>
struct S { };
template<typename T>
struct S<T, typename std::enable_if<std::is_integral<T>::value>::type>
{
T operator()() { return 42; }
};
template<typename T>
struct S<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
{
T operator()() { return 42.42; }
};
int main()
{
S<int> si;
S<float> sf;
int integer = si();
float float_ = sf();
cout << "INTEGER: " << integer << endl;
cout << "FLOAT: " << float_ << endl;
}
That said, this is a snippet involving integer and float as from in your example.
Anyway, to do that what I think you want to do, you can rely as an example on well known patterns like the abstract factory or the family of creational patterns, instead of relying on templates.
int integer = test<int>("int");
works.
And you don't need to pass "int" as string, if the <> type
is int or float is detectable by code in the function.
PS: "floateger"?
As far as I know it is not possible to achieve such functionality to return different types upon string parsing. (I assume that string is result of user input). C++ is strong typed language type so compiler must know exact return type. If string value is hard-coded you can change implementation to:
template<typename T>
T test()
{
int integer = 42;
float floateger = 42.42;
if (std::is_same<T, int>::value)
return integer;
else
return floateger;
}
int main()
{
int integer = test<int>();
cout << "INTEGER: " << integer << endl;
}
Or if you are not limited to POD types look at #molbdnilo or #skyking answers.
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.
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'