Let me set the scene..
You can open files in a specific mode like this:
#include <fstream>
int main(){
std::fstream myfile;
myfile.open ("filename", std::ios::app);
return 0;
}
that second parameter is an enumerated type-
which is why you will get a compiler error attempting this:
#include <fstream>
int main(){
std::fstream myfile;
myfile.open ("filename", std::ios::lksdjflskdjflksff);
return 0;
}
In this example, the class doesn't have to account for the second parameter being incorrect, and the programmer never has to worry about passing in a nonsensical value.
Question: Is there a way to write functions that must take a particular type AND a particular value?
Let's say I wanted to re-implement a File Handling class similar to the one above.
The difference is I'm making the second parameter a char instead of an enumerated type.
How could I get something like this to work:
#include "MyFileHandler.h"
int main(){
MyFileHandler myfile1;
myfile.open ("filename", 'a'); //GOOD: a stands for append
myfile.open ("filename", 't'); //GOOD: t stands for truncate
myfile.open ("filename", 'x'); //COMPILER ERROR: openmode can not be the value 'x'
return 0;
}
Going beyond this, can I get the compiler to test the validity of argument values through functional means?
Example:
void IOnlyAcceptPrimeNumbers(const int & primeNumber);
int function(void);
int main(){
IOnlyAcceptPrimeNumbers(3); //GOOD: 3 is prime
IOnlyAcceptPrimeNumbers(7); //GOOD: 7 is prime
IOnlyAcceptPrimeNumbers(10); //COMPILER ERROR: 10 is not prime
IOnlyAcceptPrimeNumbers(10+1); //GOOD: 11 is prime
IOnlyAcceptPrimeNumbers(1+1+1+1); //COMPILER ERROR: 4 is not prime
IOnlyAcceptPrimeNumbers(function()); //GOOD: can this somehow be done?
return 0;
}
void IOnlyAcceptPrimeNumbers(const int & primeNumber){return;}
int function(void){return 7;}
I believe i've made it clear what I want to do and why I find it important.
Any solutions out there?
If you want compile-time checked values, you could write templates rather than function arguments:
template <char> void foo(std::string const &); // no implementation
template <> void foo<'a'>(std::string const & s) { /* ... */ }
template <> void foo<'b'>(std::string const & s) { /* ... */ }
Usage:
foo<'a'>("hello world"); // OK
foo<'z'>("dlrow olleh"); // Linker error, `foo<'z'>` not defined.
If you want an actual compiler error rather than just a linker error, you could add a static_assert(false) into the primary template.
No, if you specify that your function will take a char, it will take any char.
The "resolution" used by the compiler for checking passed arguments is the type rather than a set of possible values.
In other words, you need to use enumerations for this, or move the checking to runtime, or do something horrid like:
static void processAorT (char typ, char *fileName) { ... }
void processA (char *fileName) { processAorT ('a', fileName); }
void processT (char *fileName) { processAorT ('t', fileName); |
(not something I would advise, by the way).
Having said that, I'm not sure what you're proposing is a good idea anyway.
The compiler may be able to detect invalid constants, but won't be very successful if the parameter passed into IOnlyAcceptPrimeNumbers has come from a variable or, worse, input by a user.
The API is a contract between caller and function and, if the rules of that contract are not followed, you're free to do whatever you want, though hopefully you'd document it.
In other words, that function should begin:
void IOnlyAcceptPrimeNumbers (int num) {
if (!isPrime (num)) return;
// do something with a prime number.
}
(or the equivalent for your function that accepts a and t but not x). Doing nothing when passed invalid parameters is a reasonable strategy, as is returning an error or throwing an exception (though no doubt some would argue with this).
How you handle it is up to you, but it needs to be handled at runtime simply because the compiler doesn't have all the information.
You can only check value validity at runtime. Best you can do is use assert to stop programm execution if precondition is violated.
No. If you want to restrict the accepted arguments you need to use enums or accept an object that inherits from a specific interface (depends how sophisticated you want to make it). Enums is the common way to address this issue.
The example about the IOnlyAcceptPrimeNumbers is not well designed. If you want to achieve something similar it would be better to provide a class method that is something such as bool setNumber(int number) that will return false if the number is not prime. If you want to do it in the costructor the real alternative is to throw an exception (that is not really nice to do).
The concept is that you can not simply rely that the user will pass you only elements from a (correct) subset of the values that the parameter type allows.
While more restrictive than your requirements (this limits the values a particular type can hold), you can always try something like:
// Vowel.h
#ifndef VOWEL_H_
#define VOWEL_H_
class Vowel
{
public:
static const Vowel A;
static const Vowel E;
static const Vowel I;
static const Vowel O;
static const Vowel U;
char get() const { return value; }
private:
explicit Vowel(char c);
char value;
};
#endif /* VOWEL_H_ */
// Vowel.cpp
#include "Vowel.h"
Vowel::Vowel(char c) : value(c) {}
const Vowel Vowel::A('A');
const Vowel Vowel::E('E');
const Vowel Vowel::I('I');
const Vowel Vowel::O('O');
const Vowel Vowel::U('U');
Since the char constructor is private, only Vowel itself can construct objects from chars. All other uses are done by copy construction or copy assignment.
(I think I originally learned this technique from Scott Meyers; thank him / blame me.)
Related
#include <iostream>
#include <map>
using namespace std;
string read(string a){return "abc";}
void read(float a){}
bool read(int a){return true;}
int main()
{
map<string,string(*)(string)> f1;
map<string,void(*)(float)> f2;
map<string,bool(*)(int)> f3;
f1["read"]=read;
f2["read"]=read;
f3["read"]=read;
string t,u;
while(1)
{
cin>>t>>u;
if(!f1.count(t)||!f2.count(t)||!f3.count(t)) cout<<"Unknown command!\n";
else cout<<f1[t](u);
}
}
Here I want to access these overloaded functions through their keys. But how can I (or can I ever) store them all in one single map? Something like map<string,/*---*/> f; that is capable of mapping different functions that have different parameter types and different return types so that I can use f["read"]=read; at once?
You cannot have a set of overloads as one element in a map. You could put some objects in the map that have overloaded member functions, though that also wont help, as you want elements in the map with different overloads.
Next problem is that when the parameters are from user input, you need to decide what overload you want to call before you call it. Usually you let the compiler decide based on paramters, but here you need to parse user input to the type of the parameters.
Further, elements in the map must all be of same type. That type should provide an interface that allows you to call the functions in a convenient way.
In other words, the easy way is to wrap functions into something that always takes the same paramter and always returns the same and then put that something into the map. I suggest to use std::istream for input and std::ostream for output :
#include <iostream>
#include <map>
#include <functional>
std::string read(std::string a){return "abc";}
void read(float a){}
bool read(int a){return true;}
int main()
{
std::map<std::string,std::function< void(std::istream&,std::ostream&)>> f;
f["read"] = [](std::istream& in,std::ostream& out){
std::string input;
in >> input;
// put logic to decide what overload to call here
bool call_string = true;
bool call_int = false;
bool call_bool = false;
if (call_string) {
out << read("foo");
} else if (call_int) {
out << read(42);
} else if (call_bool) {
//note : read(bool) returns void
read(false);
};
// use the map:
std::string t;
std::cin >> t;
f[t](std::cin,std::cout);
}
For input "read 42" the output is
abc
Live Example
PS: I you wouldn't insist on overloads the parsing could be automated to some extend by deducing the argument and return types of the functions to be put in the map, though it wont work with overloads (and would be a different question).
I handled the case according to #idclev 463035818's first suggestions, thanks to them.
Here's my recent sample;
#include <iostream>
#include <fstream>
#include <map>
using namespace std;
typedef string (*func)(string);
struct demo
{
map<string,func> f;
}g;
string read_p(string),read(string),read(int);
int main()
{
g.f["read"]=read_p;
while(1)
{
cout<<">>";
string t;
getline(cin,t);
size_t found=t.find(" ");
if(found==-1){if(!g.f.count(t)) cout<<"Unrecognized command!\n"; else cout<<g.f[t](t);}
else
{
string a=t.substr(0,found),b=t.substr(found+1,t.length()-found);
if(!g.f.count(a)) cout<<"Unrecognized long command!\n"; else cout<<g.f[a](b);
}
}
return 0;
}
string read_p(string c)
{
if(c=="read") return "Read what?\n";
else if(c=="story") return read(c);
else if(c.substr(0,4)!="page") return "Can't read that!\n";
else
{
size_t found=c.find_first_of("0123456789");
if(found==-1) return "Choose a page!\n";
else
{
int d=atoi((c.substr(found,2)).c_str());
return read(d);
}
}
}
string read(string a)
{
ifstream counter("game.txt",ifstream::in);
string x3;
int line=0;
while(counter.good()){getline(counter,x3); line++;}
counter.close();
string x1[line],x2="\"";
ifstream x("game.txt",ifstream::in);
for(int i=0; i<line; i++)
{
getline(x,x1[i]);
x1[i].erase(0,3);
x2.append(x1[i]+"\n");
}
x.close();
x2.erase(x2.length()-2,2);
x2.append("\"\n");
return x2;
}
string read(int a)
{
if(a<14||a>18) return "Choose another page!\n";
int page=-1;
ifstream x("game.txt",ifstream::in);
string x1;
while(a!=page){getline(x,x1); page=atoi((x1.substr(0,2)).c_str());}
x1.erase(0,3);
x1.insert(0,"\"");
x1.append("\"\n");
return x1;
}
I put the map into a struct so it's also accessible from local functions. Then when anything begins with "read" is entered, program calls read_p function with the user-input string as parameter. read_p parses that in my easy way and decides which variation of read to call. read is overloaded to be able to handle strings and integers separately. When a string is passed as parameter, read(string a) is called; and when an int is passed, read(int a) is called.
This method works precisely. Mapping the functions that are in the same format and that will parse input, then overloading different functions related to them. If any other user-input commands to be added, we'll just add g.f["command"]=command_p; that will parse it and overloaded variations of the function command. I'm sure there must be better ways, if anyone wants to help, I'll be glad about it.
Something similar to what you suggested is used by Qt framework for event handling. Said framework casts all slot function pointers to void* and is cast back before use. The code generation for that is done by meta-object compiler.
I suspect its a implementation-defined behavior that actually is viable on most of platforms as longs as you properly track which pointer points at which function. Lately their design became more complex to support lambda expressions for handlers.
I'm trying to implement a minheap in C++. However the following code keeps eliciting errors such as :
heap.cpp:24:4: error: cannot convert 'complex int' to 'int' in assignment
l=2i;
^
heap.cpp:25:4: error: cannot convert 'complex int' to 'int' in assignment
r=2i+1;
^
heap.cpp: In member function 'int Heap::main()':
heap.cpp:47:16: error: no matching function for call to 'Heap::heapify(int [11], int&)'
heapify(a,i);
^
heap.cpp:47:16: note: candidate is:
heap.cpp:21:5: note: int Heap::heapify(int)
int heapify(int i) //i is the parent index, a[] is the heap array
^
heap.cpp:21:5: note: candidate expects 1 argument, 2 provided
make: * [heap] Error 1
#include <iostream>
using namespace std;
#define HEAPSIZE 10
class Heap
{
int a[HEAPSIZE+1];
Heap()
{
for (j=1;j<(HEAPISZE+1);j++)
{
cin>>a[j];
cout<<"\n";
}
}
int heapify(int i) //i is the parent index, a[] is the heap array
{
int l,r,smallest,temp;
l=2i;
r=2i+1;
if (l<11 && a[l]<a[i])
smallest=l;
else
smallest=i;
if (r<11 && a[r]<a[smallest])
smallest=r;
if (smallest != i)
{
temp = a[smallest];
a[smallest] = a[i];
a[i]=temp;
heapify(smallest);
}
}
int main()
{
int i;
for (i=1;i<=HEAPSIZE;i++)
{
heapify(a,i);
}
}
}
Ultimately, the problem with this code is that it was written by someone who skipped chapters 1, 2 and 3 of "C++ for Beginners". Lets start with some basics.
#include <iostream>
using namespace std;
#define HEAPSIZE 10
Here, we have included the C++ header for I/O (input output). A fine start. Then, we have issued a directive that says "Put everything that is in namespace std into the global namespace". This saves you some typing, but means that all of the thousands of things that were carefully compartmentalized into std:: can now conflict with names you want to use in your code. This is A Bad Thing(TM). Try to avoid doing it.
Then we went ahead and used a C-ism, a #define. There are times when you'll still need to do this in C++, but it's better to avoid it. We'll come back to this.
The next problem, at least in the code you posted, is a misunderstanding of the C++ class.
The 'C' language that C++ is based on has the concept of a struct for describing a collection of data items.
struct
{
int id;
char name[64];
double wage;
};
It's important to notice the syntax - the trailing ';'. This is because you can describe a struct and declare variables of it's type at the same time.
struct { int id; char name[64]; } earner, manager, ceo;
This declares a struct, which has no type name, and variables earner, manager and ceo of that type. The semicolon tells the compiler when we're done with this statement. Learning when you need a semicolon after a '}' takes a little while; usually you don't, but in struct/class definition you do.
C++ added lots of things to C, but one common misunderstanding is that struct and class are somehow radically different.
C++ originally extended the struct concept by allowing you to describe functions in the context of the struct and by allowing you to describe members/functions as private, protected or public, and allowing inheritance.
When you declare a struct, it defaults to public. A class is nothing more than a struct which starts out `private.
struct
{
int id;
char name[64];
double wage;
};
class
{
public:
int id;
char name[64];
double wage;
};
The resulting definitions are both identical.
Your code does not have an access specifier, so everything in your Heap class is private. The first and most problematic issue this causes is: Nobody can call ANY of your functions, because they are private, they can only be called from other class members. That includes the constructor.
class Foo { Foo () {} };
int main()
{
Foo f;
return 0;
}
The above code will fail to compile, because main is not a member of Foo and thus cannot call anything private.
This brings us to another problem. In your code, as posted, main is a member of Foo. The entry point of a C++ program is main, not Foo::main or std::main or Foo::bar::herp::main. Just, good old int main(int argc, const char* argv[]) or int main().
In C, with structs, because C doesn't have member functions, you would never be in a case where you were using struct-members directly without prefixing that with a pointer or member reference, e.g. foo.id or ptr->wage. In C++, in a member function, member variables can be referenced just like local function variables or parameters. This can lead to some confusion:
class Foo
{
int a, b;
public:
void Set(int a, int b)
{
a = a; // Erh,
b = b; // wat???
}
};
There are many ways to work around this, but one of the most common is to prefix member variables with m_.
Your code runs afoul of this, apparently the original in C passed the array to heapify, and the array was in a local variable a. When you made a into a member, leaving the variable name exactly the same allowed you not to miss the fact that you no-longer need to pass it to the object (and indeed, your heapify member function no-longer takes an array as a pointer, leading to one of your compile errors).
The next problem we encounter, not directly part of your problem yet, is your function Heap(). Firstly, it is private - you used class and haven't said public yet. But secondly, you have missed the significance of this function.
In C++ every struct/class has an implied function of the same name as the definition. For class Heap that would be Heap(). This is the 'default constructor'. This is the function that will be executed any time someone creates an instance of Heap without any parameters.
That means it's going to be invoked when the compiler creates a short-term temporary Heap, or when you create a vector of Heap()s and allocate a new temporary.
These functions have one purpose: To prepare the storage the object occupies for usage. You should try and avoid as much other work as possible until later. Using std::cin to populate members in a constructor is one of the most awful things you can do.
We now have a basis to begin to write the outer-shell of the code in a fashion that will work.
The last change is the replacement of "HEAPSIZE" with a class enum. This is part of encapsulation. You could leave HEAPSIZE as a #define but you should expose it within your class so that external code doesn't have to rely on it but can instead say things like Heap::Size or heapInstance.size() etc.
#include <iostream>
#include <cstdint> // for size_t etc
#include <array> // C++11 encapsulation for arrays.
struct Heap // Because we want to start 'public' not 'private'.
{
enum { Size = 10 };
private:
std::array<int, Size> m_array; // meaningful names ftw.
public:
Heap() // default constructor, do as little as possible.
: m_array() // says 'call m_array()s default ctor'
{}
// Function to load values from an istream into this heap.
void read(std::istream& in)
{
for (size_t i = 0; i < Size; ++i)
{
in >> m_array[i];
}
return in;
}
void write(std::ostream& out)
{
for (size_t i = 0; i < Size; ++i)
{
if (i > 0)
out << ','; // separator
out << m_array[i];
}
}
int heapify(size_t index)
{
// implement your code here.
}
}; // <-- important.
int main(int argc, const char* argv[])
{
Heap myHeap; // << constructed but not populated.
myHeap.load(std::cin); // read from cin
for (size_t i = 1; i < myHeap.Size; ++i)
{
myHeap.heapify(i);
}
myHead.write(std::cout);
return 0;
}
Lastly, we run into a simple, fundamental problem with your code. C++ does not have implicit multiplication. 2i is the number 2 with a suffix. It is not the same as 2 * i.
int l = 2 * i;
There is also a peculiarity with your code that suggests you are mixing between 0-based and 1-based implementation. Pick one and stick with it.
--- EDIT ---
Technically, this:
myHeap.load(std::cin); // read from cin
for (size_t i = 1; i < myHeap.Size; ++i)
{
myHeap.heapify(i);
}
is poor encapsulation. I wrote it this way to draw on the original code layout, but I want to point out that one reason for separating construction and initialization is that it allows initialization to be assured that everything is ready to go.
So, it would be more correct to move the heapify calls into the load function. After all, what better time to heapify than as we add new values, keeping the list in order the entire time.
for (size_t i = 0; i < Size; ++i)
{
in >> m_array[i];
heapify(i);
}
Now you've simplified your classes api, and users don't have to be aware of the internal machinery.
Heap myHeap;
myHeap.load(std::cin);
myHeap.write(std::cout);
I was trying to make a program, which automatically detects the data type of input given by user.
My approach :
int input(istream& i)
{
int k;
i>>k;
return k;
}
float input(istream& i)
{
float k;
i>>k;
return k;
}
void showval(int h){cout<<h;}
void showval(float h){cout<<h;}
int main()
{
showval(input(cin));
return 0;
}
As you can see, I used overloading of parameters and overloading of return type of two different functions, but at the same time. However, the program gives error as
"new declaration float input(istream& i) disambiguates the old
declaration int input(istream& i)”.
I don’t understand, how this creates ambiguity. Is it because, the two different functions (showval and input) are dependent?
Also after going through few articles on overloading, what i realised is that in C++, methods can be overloaded only if they differ by parameters.
However this link has a trick by which he was able to overload functions by return type. Is it possible to use the same trick in my program? Also, is there any way by which i can tell the compiler that the function input has parameter which is user dependent, and its data type may or may not differ. Does C++ forbid such possibilty?
Let's say that types such as int and float are specific, and types such as the proxy object shown in the linked question are generic. Our options are to be specific to begin with, in which case we just coast through the rest, or we give rise to a generic type and handle all the various specific types we may support.
The proxy object shown in the linked question is an example of a variant type, and boost::variant is a generic implementation of this. For example, boost::variant<int, float> allows us to hold either int or float.
My recommendation really depends what you want. Do you
want to specify the type you expect to get from the user and throw on unexpectd input? (specific to begin with and coast) OR,
want to give rise to a different type depending on what the user inputted and specify a set of types you can handle? (Give rise to a generic type and handle the various specific types)
Specifying the type you expect from the user
In this case we can simply make the function templated and we specify the type we expect through the template parameter.
The example shown is kept totally generic but you can restrain template parameters using various techniques. Check out my answer regarding this topic.
#include <iostream>
/* Read data of type T from an input stream. */
template <typename T>
T read(std::istream &strm) {
T val;
strm >> val;
if (!strm) {
throw /* something */;
} // if
return val;
}
/* Print data of type T. */
template <typename T>
void print(const T &val) {
std::cout << val;
}
int main() {
print(read<int>(std::cin));
}
This will give rise to an int for input such as 1 and even for input such as 1., 1.0 and 1.2.
Handling different types you may get from the user
In this case we're actually lexing the input stream from the user. Our read function will give rise to a generic type, boost::variant<int, float>.
#include <iostream>
#include <boost/variant.hpp>
/* Naive implementation of a lexer. */
boost::variant<int, float> read(std::istream &strm) {
std::string lexeme;
strm >> lexeme;
try {
std::size_t idx;
auto val = std::stoi(lexeme, &idx);
if (idx == lexeme.size()) { // Make sure we converted the entire lexeme.
return val;
} // if
} catch (const std::exception &) {
// Do nothing. We'll try to lex it as float instead.
} // try
std::size_t idx;
auto val = std::stof(lexeme, &idx);
if (idx == lexeme.size()) { // Make sure we converted the entire lexeme.
return val;
} // if
throw /* something */;
}
/* Print the type and the value, to check that we have the correct type. */
void print(const boost::variant<int, float> &val) {
class visitor : public boost::static_visitor<void> {
public:
void operator()(int that) const {
std::cout << "int: " << that << std::endl;
}
void operator()(float that) const {
std::cout << "float: " << that << std::endl;
}
}; // visitor
boost::apply_visitor(visitor(), val);
}
int main() {
print(read(std::cin));
}
This approach will give rise to int for input such as 1, and give rise to float for input such as 1., 1.0 as 1.2.
As you can see, we give rise to a generic type, boost::variant<int, float>, and handle the various specific types, int and float, in the visitor.
The problem is that the compiler cannot possibly know which version of input to call. It is only within input that you actually attempt to extract from the stream, and only at that point can you know what the user has inputted. And even then, there's no reason the user can't enter 1.5 and then you extract into an int, or they enter 5 and you extract into a float.
Types are compile-time constructs. The compiler uses the type information to produce the program executable, so it must know what types are being used at compile time (way before the user inputs anything).
So no, you can't do this quite like this. You could extract a line from the input, parse it to determine whether it's a floating point value or an integer (does it have a .?), and then have a separate execution path for each case. However, instead I recommend deciding what the input that you expect from the user is (an int or a float?) and just extract that.
And also no, the trick with the proxy won't work for you. Firstly, as I mentioned, the format of the input is not known at compile time anyway. But secondly, in that code, the type that was required was known by the type of the variable being declared. In one line they did int v = ... and in the other they did double u = .... In your case, you're passing the result to showval which could take either an int or double and the compiler has no idea which.
I need to find some way to mock an overload of a function return type in C++.
I know that there isn't a way to do that directly, but I'm hoping there's some out-of-the-box way around it.
We're creating an API for users to work under, and they'll be passing in a data string that retrieves a value based on the string information. Those values are different types. In essence, we would like to let them do:
int = RetrieveValue(dataString1);
double = RetrieveValue(dataString2);
// Obviously, since they don't know the type, they wouldn't use int =.... It would be:
AnotherFunction(RetrieveValue(dataString1)); // param of type int
AnotherFunction(RetrieveValue(dataString2)); // param of type double
But that doesn't work in C++ (obviously).
Right now, we're having it set up so that they call:
int = RetrieveValueInt(dataString1);
double = RetrieveValueDouble(dataString2);
However, we don't want them to need to know what the type of their data string is.
Unfortunately, we're not allowed to use external libraries, so no using Boost.
Are there any ways we can get around this?
Just to clarify, I understand that C++ can't natively do it. But there must be some way to get around it. For example, I thought about doing RetrieveValue(dataString1, GetType(dataString1)). That doesn't really fix anything, because GetType also can only have one return type. But I need something like that.
I understand that this question has been asked before, but in a different sense. I can't use any of the obvious answers. I need something completely out-of-the-box for it to be useful to me, which was not the case with any of the answers in the other question asked.
You've to start with this:
template<typename T>
T RetrieveValue(std::string key)
{
//get value and convert into T and return it
}
To support this function, you've to work a bit more, in order to convert the value into the type T. One easy way to convert value could be this:
template<typename T>
T RetrieveValue(std::string key)
{
//get value
std::string value = get_value(key, etc);
std::stringstream ss(value);
T convertedValue;
if ( ss >> convertedValue ) return convertedValue;
else throw std::runtime_error("conversion failed");
}
Note that you still have to call this function as:
int x = RetrieveValue<int>(key);
You could avoid mentioning int twice, if you could do this instead:
Value RetrieveValue(std::string key)
{
//get value
std::string value = get_value(key, etc);
return { value };
}
where Value is implemented as:
struct Value
{
std::string _value;
template<typename T>
operator T() const //implicitly convert into T
{
std::stringstream ss(_value);
T convertedValue;
if ( ss >> convertedValue ) return convertedValue;
else throw std::runtime_error("conversion failed");
}
}
Then you could write this:
int x = RetrieveValue(key1);
double y = RetrieveValue(key2);
which is which you want, right?
The only sane way to do this is to move the return value to the parameters.
void retrieve_value(std::string s, double& p);
void retrieve_value(std::string s, int& p);
<...>
double x;
retrieve_value(data_string1, x);
int y;
retrieve_value(data_string2, y);
Whether it is an overload or a specialization, you'll need the information to be in the function signature. You could pass the variable in as an unused 2nd argument:
int RetrieveValue(const std::string& s, const int&) {
return atoi(s.c_str());
}
double RetrieveValue(const std::string& s, const double&) {
return atof(s.c_str());
}
int i = RetrieveValue(dataString1, i);
double d = RetrieveValue(dataString2, d);
If you know your value can never be something like zero or negative, just return a struct holding int and double and zero out the one you don't need...
It's a cheap and dirty, but easy way...
struct MyStruct{
int myInt;
double myDouble;
};
MyStruct MyFunction(){
}
If the datastrings are compile-time constants (as said in answering my comment), you could use some template magic to do the job. An even simpler option is to not use strings at all but some data types which allow you then to overload on argument.
struct retrieve_int {} as_int;
struct retrieve_double {} as_double;
int RetrieveValue(retrieve_int) { return 3; }
double RetrieveValue(retrieve_double) { return 7.0; }
auto x = RetrieveValue(as_int); // x is int
auto y = RetrieveValue(as_double); // y is double
Unfortunately there is no way to overload the function return type see this answer
Overloading by return type
int a=itoa(retrieveValue(dataString));
double a=ftoa(retrieveValue(dataString));
both return a string.
As an alternative to the template solution, you can have the function return a reference or a pointer to a class, then create subclasses of that class to contain the different data types that you'd like to return. RetrieveValue would then return a reference to the appropriate subclass.
That would then let the user pass the returned object to other functions without knowing which subclass it belonged to.
The problem in this case would then become one of memory management -- choosing which function allocates the returned object and which function deletes it, and when, in such a way that we avoid memory leaks.
The answer is simple just declare the function returning void* type and in the definition return a reference to the variable of different types. For instance in the header (.h) declare
void* RetrieveValue(string dataString1);
And in the definition (.cpp) just write
void* RetrieveValue(string dataString1)
{
if(dataString1.size()<9)
{
static double value1=(double)dataString1.size();
return &value1;
}
else
{
static string value2=dataString1+"some string";
return &value2;
}
}
Then in the code calling RetrieveValue just cast to the right value
string str;
string str_value;
double dbl_value;
if(is_string)
{
str_value=*static_cast<*string>(RetrieveValue(str));
}
else
{
dbl_value=*static_cast<*double>(RetrieveValue(str));
}
Since you used an example that wasn't really what you wanted, you threw everyone off a bit.
The setup you really have (calling a function with the return value of this function whose return type is unknowable) will not work because function calls are resolved at compile time.
You are then restricted to a runtime solution. I recommend the visitor pattern, and you'll have to change your design substantially to allow for this change. There isn't really another way to do it that I can see.
I want to write a C++11 function that will only accept string literals as a parameter:
void f(const char* s) { static_assert(s is a string literal); ... }
That is:
f("foo"); // OK
char c = ...;
f(&c); // ERROR: Doesn't compile
string s = ...;
f(s.c_str()); // ERROR: Doesn't compile
etc
Is there anyway to implement this? The signature of the function is open to changes, as is adding the use of macros or any other language feature.
If this is not possible what is the closest approximation? (Can user-defined literals help in anyway?)
If not is there a platform specific way in GCC 4.7 / Linux ?
I think the closest you are going to get is this
template<int N>
void f(const char (&str)[N]){
...
}
It will compile with literals and arrays but not pointers.
An alternative might be to make a GCC extension to check at compile time that your particular function is only called with a literal string.
You could use MELT to extend GCC. MELT is a high-level domain specific language to extend the GCC compiler, and is very well suited for the kind of check you want.
Basically, you would add a new pass inside GCC and code that pass in MELT which would find every gimple which is a call to your function and check that the argument is indeed a literal string. The ex06 example on melt-examples should inspire you. Then subscribe to gcc-melt#googlegroups.com and ask your MELT specific questions there.
Of course, this is not a foolproof approach: the function could be called indirectly thru pointers, and it could e.g. have a partial literal string, e.g. f("hello world I am here"+(i%4)) is conceptually a call with some literal string (e.g. in .rodata segment), but not in the generated code nor in the gimple.
I use this :
// these are used to force constant, literal strings in sqfish binding names
// which allows to store/copy just the pointer without having to manage
// allocations and memory copies
struct _literalstring
{
// these functions are just for easy usage... not needed
// the struct can be empty
bool equal(_literalstring const *other) { return !strcmp((const char *)this, (const char *)other); }
bool equal(const char *other) { return !strcmp((const char *)this, other); }
const char *str(void) { return (const char *)this; }
bool empty(void) { return *(const char *)this == 0; }
};
typedef _literalstring *LITSTR;
constexpr LITSTR operator "" _LIT(const char *s, size_t) {
return (LITSTR)s;
}
Then you just declare your function like this :
void myFunc(LITSTR str)
{
printf("%s\n", str->str());
printf("%s\n", (const char *)str);
const char *aVar = str->str();
const char *another = (const char *)str;
}
And you call it like this:
myFunc("some text"_LIT);
If you do something like this:
myFunc("some text");
myFunc(aTextVariable);
you get a compiler error.