In Javascript or ActionScript it's possible to pass an object to a function or a constructor.
myfunction({myParam:1, myOtherParam:"hello"});
It is very useful when you have a lot of parameters to pass, IMO it makes using functions easier than using the classic approach.
myFunction(1,"hello");
Is there something similar in C++?
TIA
boost parameter http://www.boost.org/doc/libs/release/libs/parameter/ do exactly what you want.
From its abstract:
Use this library to write functions and class templates that can
accept arguments by name
Small example:
// include boost parameter
#include <boost/parameter/keyword.hpp>
namespace parameter = boost::parameter;
// first declare named parameters
BOOST_PARAMETER_NAME(a) // Note: no semicolon
BOOST_PARAMETER_NAME(b)
// then declare your function
BOOST_PARAMETER_FUNCTION(
(int), // 1. parenthesized return type
my_function, // 2. name of the function
tag, // 3. namespace of tag types (don't change!)
(required (a, int) ) // 4. one required parameter of type int
(optional // and an optional parameters, with default value
(b, int, 0)
)
)
{
return a + b;
}
// then you can call it with no named parameters
int result = my_function(1, 2);
// or with named parameters
int result = my_function(_a=1, _b=2);
// also with optional parameters omitted
int result = my_function(_a=3);
You can use the "named parameter idiom":
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.20
Which would make your call look like:
f(1).myOtherParam("Hello")
See here for a comparison with Boost parameter.
One could use structures:
struct foo {
int a,b,c;
float f;
}
Sadly, you need to define them somewhere and the receiving function needs to accept them, you can't just make them up in-place.
At the end of the day, there's no language tool in C++ that could mimic the JavaScript 'idiom'. Such stuff lies in the nature of a dynamic language, which C++ is not.
Yes.
In C++, an object is an instance of a class. You could create a class holding all the possible arguments, instantiate it and fill it with your particular values, and then pass that instance to the function.
You cannot just pass an arbitrary object instead of the function's arguments, because C++ doesn't have named arguments - only the position matters, and the position within some kind of hash structure is lost. So you can't say foo(y=3) when you have a function foo(int x, int y) because the names x and y only have meaning within the function - not to its callers.
No, not really. There is a map class in the standard library, and of course you could write a function that accepted a map full of named values as input, but there's nothing that exists directly as a language feature equivalent to what you've shown.
As several other posters have pointed out, of course you can define a class to hold all the data values, but this just pushes the ordered parameter list from the function to the constructor of that object, so it buys you nothing at all.
Use structs or classes to group your data.
If you're looking for a way to pass key value pairs, use STL maps
Not at the language level, but:
It is very useful when you have a lot of parameters to pass, IMO it makes using functions easier than using the classic approach.
You should really consider cutting down on your parameters if you can. Often this can be achieved by using aggregates:
Example:
draw_rectangle(x1, y1, x2, y2, r, g, b, a)
Could be reduced to:
draw_rectangle(p1, p2, color)
Or even further:
draw_rectangle(rect, color)
The temptation for named parameters should be mitigated considerably if you do this.
You can also use alternative approaches like Boost Parameter which, through a lot of template magic, accomplishes something like this. However, it requires you turn all your functions using this technique into templates written in a very precise way, and it's a very bulky and heavy-handed attempt to force the language to do something it wasn't designed to do if you ask me.
You can do the following, which supports default values to a limited amount (limited by the template system of C++). You will need to compile this with the newest standard (C++11)
// used to skip arguments and default to the previously specified value
struct UseDefault {
// empty intentionally!
};
// using this is optional, and only required if you want to provide default values by the CALLED function
template <typename T, T def> struct Default {
T value;
operator T() {
return value;
}
Default(T value) : value(value) {}
Default(UseDefault ignore) : value(def) {(void)ignore;}
};
// using tuple, you can bundle any number of parameters to one
int myFunc(std::tuple<Default<int,7>,Default<char,'x'>,std::string> parameters) {
std::cout << std::get<0>(parameters) << ", " << std::get<1>(parameters) << std::endl;
return 0;
}
You can then invoke myFunc like this:
func(std::make_tuple(6,UseDefault(),"hi"));
Note however, that there are some limitation to the template parameter types, for instance, you cannot pass strings (or char*s for that matter) as template parameters. However, if you only need reasonable basic default values, this could work.
Of course if you drop your requirement to specify default values, you can simply use the std::tuple without my Default type.
Related
I'm currently writing a function which will take a variable number of arguments. I pass the number of arguments into the function and then will iterate through the arguments list.
Each of the passed arguments should be an integer. I will be adding this integer to a vector of integers which will be used later.
I would like to make sure that some joker doesn't attempt to pass this function something other then an integer in the future. I recognize that I can check the current argument from va_arg to ensure it is not NULL and I can use something like isanum(va_arg()) to determine if it is a valid integer. I suppose I could even check the sizeof(va_arg) and compare it against the sizeof(int) and ensure they are equal.
Are there any other checks which I can run to verify I have been passed a valid integer?
Thanks in advance for assistance
There is no sensible way you can do this. Variable-argument functions work by concatenating all the raw binary representations of the arguments into one big chunk of data on the stack. So it relies on both the caller and the callee agreeing on what the number and type of arguments are (otherwise you'll end up reading e.g. an int as if it were a float).
As to your specific ideas:
va_arg() is a macro that simply interprets some number of bytes of the raw stack data as whatever type you specify. So invoking sizeof() on it will simply tell you the size of the data type you asked for.
In general, there are no patterns of raw binary data that form an invalid integer. So the hypothetical isanum() could not work.
Each of the passed arguments should be an integer.
If you have a C++0x compiler, I suggest an initializer_list<int> instead of varargs:
#include <initializer_list>
void foo(std::initializer_list<int> numbers)
{
my_vector.insert(my_vector.end(), numbers.begin(), numbers.end());
}
int main()
{
foo( {2, 3, 5, 7} );
}
This is straight-forward and completely type-safe.
Each of the passed arguments should be
an integer. I will be adding this
integer to a vector of integers which
will be used later.
Then why not just accept a vector of integers?
void AddIntegers(const std::vector<int>& vec);
You can then always concatenate vectors together using iterators.
Or make an interface like this:
void AddInteger(int newInt);
Or even this:
void AddIntegers(const int* integers, unsigned int numIntegers);
template <unsigned int Size>
void AddIntegers(int (&integers)[Size])
{
AddIntegers(integers, Size);
}
int main()
{
int i[] = {1, 2, 3, 4};
AddIntegers(i);
}
These will work if you need to work with a C++03 compiler. If you have a C++0x compiler, there are far superior solutions available.
Variable arguments are unsafe by design. You cannot check that the user passed correct type in any way. C++0x comes to the rescue with variadic templates but not many compilers support it nowadays (only GCC afaik).
Unfortunately, there really isn't a way to do this. Functions like printf() can easily be fowled up by passing invalid or the wrong number of arguments.
In C++, this is an advanced feature that requires the programming using such code to ensure the correct arguments are passed.
You can't do any sort of type checking with varargs. I'd suggest using an iterator range instead (like standard library functions) or possibly a std::vector<int>. This way the types can't be subverted.
Since you are using C++, how about overloading some operator and pass the arguments one-by-one? For example
class MyFunction {
std::vector<int> param;
public:
MyFunction() { /* some initialisation? */ }
MyFunction &operator,(int eatMe) {
param.push_back(eatMe);
return *this;
}
~MyFunction() {
//the implementation of your function goes here
}
}
Then you can call it like this:
MyFunction(),2,3,5,7;
Note, the use of comma operator may look scary, but it is actually very helpful in this case. It is the lowest possible, left-associative operator.
If your function takes some extra parameters, not only the unknown-length of int-s, you can pass them in the constructor.
If someone uses something else than int, the default comma operator will be used (evaluate left side, discard, evaluate right side). If you don't like that - pick a different operator, e.g. stream-like << or boost-like %.
If you are restricted to C++03 and all your arguments should be integers, one solution would be to simply hide the variable argument function (in a 'detail' namespace for example) and make a series of overloaded functions for 1 to N amount of arguments. Those functions would be simple inline functions that forward the call to the vararg version of the real function. This way, you have one real implementation, no run-time overhead, and you expose a type-safe interface to the caller (and the caller can always use the vararg version if he needs more than N arguments).
Boost.PP can also help to generate these types of repetitive patterns.
Of course, if you have some level of C++0x support, than the problem can be solved in many ways, including initializer_list or variadic templates.
Just to illustrate my comment on CygnusX1's answer, you could do it like:
class MyFunction {
std::vector<int> params;
public:
MyFunction() { (*this)(); }
MyFunction(int eatMe) { (*this)(eatMe); }
MyFunction& operator()(int eatMe) {
params.push_back(eatMe);
return *this;
}
void operator()() {
// use params to do something interesting
}
}
MyFunction(2)(3)(5)(7)();
This question already has answers here:
Variable number of arguments in C++?
(17 answers)
Closed 9 years ago.
I've got the class member:
LineND::LineND(double a ...)
{
coefficients.push_back(a);
va_list arguments;
va_start(arguments, a);
double argValue;
do
{
argValue = va_arg(arguments, double);
coefficients.push_back(argValue);
}while(argValue != NULL); // THIS IS A PROBLEM POINT!
va_end(arguments);
}
I don't know how many arguments will be used. I need to take each argument and put it into the vector called coefficients. How should I do that? I understand, that the statement while(argValue != NULL) is not correct in this case. I can't use for example this signature:
LineND::LineND(int numArgs, double a ...)
to change the condition like this:
while(argValue != numArgs);
The point is I can't change the signature of the method. Need to resolve this problem another way.
Variable argument lists have several drawbacks:
Callers can pass in everything they want.
If a non-POD object is passed, undefined behaviour is summoned
You can't rely on the number of arguments (the caller can make errors)
You put a LOT of responsibility on your CLIENT, for whom you intended to have an easier time with your library code (practical example: format-string-bugs/-errors)
Compared to variadic templates:
Compile time list size is known
Types are known at compile time
You have the responsibility for stuff, not your client, which is like it should be.
Example:
void pass_me_floats_impl (std::initializer_list<float> floats) {
...
}
You can put this into the private section of a class declaration or in some detail namespace. Note: pass_me_floats_impl() doesn't have to be implemented in a header.
Then here's the nice stuff for your client:
template <typename ...ArgsT>
void pass_me_floats (ArgsT ...floats) {
pass_me_floats_impl ({floats...});
}
He now can do:
pass_me_floats ();
pass_me_floats (3.5f);
pass_me_floats (1f, 2f, 4f);
But he can't do:
pass_me_floats (4UL, std::string());
because that would emit a compile error inside your pass_me_floats-function.
If you need at least, say, 2 arguments, then make it so:
template <typename ...ArgsT>
void pass_me_floats (float one, float two, ArgsT... rest) {}
And of course, if you want it a complete inline function, you can also
template <typename ...ArgsT>
void pass_me_floats (ArgsT... rest) {
std::array<float, sizeof...(ArgsT)> const floaties {rest...};
for (const auto f : floaties) {}
}
Variadic arguments are heavily frowned upon in C++, and for good reason. One of these reasons is that there is no way to know where the list ends, so if you can't change the signature of the function, you must dictate some kind of sentinel value to indicate where the list ends. If you cannot do either of those things, you are screwed.
You should rewrite the method to take std::initializer_list<double>.
If you can't do that, and can't add a count parameter, the fix is to take a sentinel value that terminates the argument list, e.g. 0.0 or NaN (or any value that doesn't make sense in your function's context).
For example, functions that take a variable number of pointers use NULL as the sentinel value; functions that take a list of structs take a 0-initialised struct as the sentinel. This is fairly common in C APIs; see http://c-faq.com/varargs/nargs.html where the example given is execl("/bin/sh", "sh", "-c", "date", (char *)NULL);
In this case, you cannot determine the number of arguments in your code. You have to make the caller of such function pass the number of doubles to you (I'm assuming the first a argument doesn't contain the number of arguments). Eg.:
LineND::LineND(unsigned count, ...)
{
va_list arguments;
va_start(arguments, a);
and the condition becomes
while (a--) { ... }
In C++11, you can use two better devices for passing unspecified number of doubles.
passing a vector and initializing it with an initializer-list
variadic templates
Note that there are differences between the two; tho former has some problems when forwarding originating from the fact that {...} is not an expression in C++. The latter can cause code bloat, because it generates a function for each combination of argument types.
In C++03, you can only use helper objects, such as those offered by the Boost.Assignment library, for passing unknown number of arguments.
Make the first double of the arguments list be the actual count of arguments.
I often use the Boost strong typedef utility to improve the safety of my programs. For example by writing code like this:
BOOST_STRONG_TYPEDEF(int, X)
BOOST_STRONG_TYPEDEF(int, Y)
BOOST_STRONG_TYPEDEF(int, Width)
BOOST_STRONG_TYPEDEF(int, Height)
struct Rect {
Rect(X x, Y y, Width w, Height h);
};
// Usage:
Rect rect(X(10), Y(20), Width(800), Height(600));
The strong typedef here improves both code readability and safety. (The compiler will report an error if the arguments are provided in the wrong order, which would not have been the case if the arguments were all int.)
My questions are:
Is it ok to use BOOST_STRONG_TYPEDEF for this purpose? (The documentation is very brief.)
Are there important reasons to prefer the boost parameter library instead?
Technically speaking:
it works
it adds type safety
Practically speaking:
I would not recommend creating new types just for the sake of a single function's parameters (unless it is an enum specific to this function), types should permeate the application to avoid casts being used over and over.
If the types X, Y, Width and Height are used throughout the application, then not only will there be no cast, but your application will be much safer and much better documented too (yeah... I am a type freak).
Now, with regard to Boost.Parameters, this is completely different.
Boost.Parameters can (potentially) be added when you have types already in place. Honestly though I never saw the need. When your functions grow so unwieldy that Boost.Parameters is required to call them, you should fix the functions, not add to the clutter.
Using BOOST_STRONG_TYPDEF is creating a new type, where as the boost parameter library is for giving names to parameters. It lets you be more explicit with what your functions take. For example (from the boost documentation)
#include <boost/parameter/preprocessor.hpp>
namespace graphs
{
BOOST_PARAMETER_FUNCTION(
(void), // 1. parenthesized return type
depth_first_search, // 2. name of the function template
tag, // 3. namespace of tag types
(required (graph, *) ) // 4. one required parameter, and
(optional // four optional parameters, with defaults
(visitor, *, boost::dfs_visitor<>())
(root_vertex, *, *vertices(graph).first)
(index_map, *, get(boost::vertex_index,graph))
(in_out(color_map), *,
default_color_map(num_vertices(graph), index_map) )
)
)
{
// ... body of function goes here...
// use graph, visitor, index_map, and color_map
}
}
Lets you explicitly say what is expected, almost in a design by contract sort of way. However I find this complicates the readability of your code enough to make it not worth doing.
Personally I prefer to use BOOST_STRONG_TYPEDEF as it creates a new types "that can be used for matching either function or template parameters" (again from the boost documentation).
I'm currently writing a function which will take a variable number of arguments. I pass the number of arguments into the function and then will iterate through the arguments list.
Each of the passed arguments should be an integer. I will be adding this integer to a vector of integers which will be used later.
I would like to make sure that some joker doesn't attempt to pass this function something other then an integer in the future. I recognize that I can check the current argument from va_arg to ensure it is not NULL and I can use something like isanum(va_arg()) to determine if it is a valid integer. I suppose I could even check the sizeof(va_arg) and compare it against the sizeof(int) and ensure they are equal.
Are there any other checks which I can run to verify I have been passed a valid integer?
Thanks in advance for assistance
There is no sensible way you can do this. Variable-argument functions work by concatenating all the raw binary representations of the arguments into one big chunk of data on the stack. So it relies on both the caller and the callee agreeing on what the number and type of arguments are (otherwise you'll end up reading e.g. an int as if it were a float).
As to your specific ideas:
va_arg() is a macro that simply interprets some number of bytes of the raw stack data as whatever type you specify. So invoking sizeof() on it will simply tell you the size of the data type you asked for.
In general, there are no patterns of raw binary data that form an invalid integer. So the hypothetical isanum() could not work.
Each of the passed arguments should be an integer.
If you have a C++0x compiler, I suggest an initializer_list<int> instead of varargs:
#include <initializer_list>
void foo(std::initializer_list<int> numbers)
{
my_vector.insert(my_vector.end(), numbers.begin(), numbers.end());
}
int main()
{
foo( {2, 3, 5, 7} );
}
This is straight-forward and completely type-safe.
Each of the passed arguments should be
an integer. I will be adding this
integer to a vector of integers which
will be used later.
Then why not just accept a vector of integers?
void AddIntegers(const std::vector<int>& vec);
You can then always concatenate vectors together using iterators.
Or make an interface like this:
void AddInteger(int newInt);
Or even this:
void AddIntegers(const int* integers, unsigned int numIntegers);
template <unsigned int Size>
void AddIntegers(int (&integers)[Size])
{
AddIntegers(integers, Size);
}
int main()
{
int i[] = {1, 2, 3, 4};
AddIntegers(i);
}
These will work if you need to work with a C++03 compiler. If you have a C++0x compiler, there are far superior solutions available.
Variable arguments are unsafe by design. You cannot check that the user passed correct type in any way. C++0x comes to the rescue with variadic templates but not many compilers support it nowadays (only GCC afaik).
Unfortunately, there really isn't a way to do this. Functions like printf() can easily be fowled up by passing invalid or the wrong number of arguments.
In C++, this is an advanced feature that requires the programming using such code to ensure the correct arguments are passed.
You can't do any sort of type checking with varargs. I'd suggest using an iterator range instead (like standard library functions) or possibly a std::vector<int>. This way the types can't be subverted.
Since you are using C++, how about overloading some operator and pass the arguments one-by-one? For example
class MyFunction {
std::vector<int> param;
public:
MyFunction() { /* some initialisation? */ }
MyFunction &operator,(int eatMe) {
param.push_back(eatMe);
return *this;
}
~MyFunction() {
//the implementation of your function goes here
}
}
Then you can call it like this:
MyFunction(),2,3,5,7;
Note, the use of comma operator may look scary, but it is actually very helpful in this case. It is the lowest possible, left-associative operator.
If your function takes some extra parameters, not only the unknown-length of int-s, you can pass them in the constructor.
If someone uses something else than int, the default comma operator will be used (evaluate left side, discard, evaluate right side). If you don't like that - pick a different operator, e.g. stream-like << or boost-like %.
If you are restricted to C++03 and all your arguments should be integers, one solution would be to simply hide the variable argument function (in a 'detail' namespace for example) and make a series of overloaded functions for 1 to N amount of arguments. Those functions would be simple inline functions that forward the call to the vararg version of the real function. This way, you have one real implementation, no run-time overhead, and you expose a type-safe interface to the caller (and the caller can always use the vararg version if he needs more than N arguments).
Boost.PP can also help to generate these types of repetitive patterns.
Of course, if you have some level of C++0x support, than the problem can be solved in many ways, including initializer_list or variadic templates.
Just to illustrate my comment on CygnusX1's answer, you could do it like:
class MyFunction {
std::vector<int> params;
public:
MyFunction() { (*this)(); }
MyFunction(int eatMe) { (*this)(eatMe); }
MyFunction& operator()(int eatMe) {
params.push_back(eatMe);
return *this;
}
void operator()() {
// use params to do something interesting
}
}
MyFunction(2)(3)(5)(7)();
I have written a function that searches a text file for names. It returns vector, where each element of the vector is a different name.
Now I would like to search the same text file for numbers and return the numbers in a vector.
This is probably a dumb question, but I'm wondering what the best approach would be. Overload the function by writing a second function that returns a vector or turning the function I have already written into a template by replacing the type with T, as in vector.
The reason I'm confused about the template option is that I'm not sure if strings and numerical types like double and int are compatible in a template. Any tips would be appreciated! Thanks.
As a function signature does not include its return type, you can't overload a function only on its return type.
Also, as the two functions returns different kind of data (one could return person names, the other could return the persons ages), having the same name for both seems a semantic error.
But anyway...
Move the return type part back into the signature
void retrieveData(std::vector<std::string> & data) ;
void retrieveData(std::vector<double> & data) ;
void foo()
{
std::vector<std::string> strings ;
std::vector<double> doubles ;
// retrieve the strings
retrieveData(strings) ;
// retrieve the numbers
retrieveData(doubles) ;
}
This solution is best both because the overload work "as is", and because it avoids a copy of the vector (I am using C++03, here... In C++0x, one would use move semantics to avoid the potential extra copy).
Make the return type part of the signature (non-template version)
std::vector<std::string> retrieveData(std::string * dummy) ;
std::vector<double> retrieveData(double * dummy) ;
void foo()
{
// retrieve the strings
std::vector<std::string> strings = retrieveData((std::string *) NULL) ;
// retrieve the numbers
std::vector<double> doubles = retrieveData((double *) NULL) ;
}
Here, the dummy parameter's pointer value is not used in the function body. It's use is to enable the compiler to find the right overload.
This is ugly (not mentioning the part on returning by copy a vector in C++03 but this is out of topic), but it does the work and is a viable answer to your question.
Make the return type part of the signature (template version)
// declared, but not defined
template<typename T>
std::vector<T> retrieveData() ;
// defined
template<>
std::vector<std::string> retrieveData<std::string>() ;
// defined
template<>
std::vector<double> retrieveData<double>() ;
void foo()
{
// retrieve the strings
std::vector<std::string> strings = retrieveData<std::string>() ;
// retrieve the numbers
std::vector<double> doubles = retrieveData<double>() ;
}
Here, the template parameter is given by the user, thus giving the compiler enough information to choose the right overload
P.S.: This answer is quite similar to the one I gave here: Overload a C++ function according to the return value
I'd just make two different functions with different names like findStrings() and findNumbers(). Overloading by return type doesn't work, templates make no sense here, and, most importantly, these functions just do different things.
However, if overloading is desired, I would do it like this:
bool findInFile(const std::string &fileName, std::vector<int> &result);
bool findInFile(const std::string &fileName, std::vector<std::string> &result);
This way overloading will work, and it also has a nice property of returning success or failure indicator if you want to avoid throwing exceptions in case of failure. Just replace it with void otherwise. But this approach has the disadvantage of being awkward to use if you need not to store the result in a variable, but pass it to some function for example.
Since you have only 1 overload to do, I would go with function overload instead of templates. I think that in this case it doesn't justify adding a bunch of code just to overload a function once.
There is maybe a case for a template function as follows:
template <typename T, typename OutputIterator>
void readTokens<T>(OutputIterator oi) {
for each token in the file {
std::stringstream ss(token);
T t;
if (ss >> t) {
*oi++ = t;
}
}
}
Then you can do readTokens<string>, readTokens<int>, readTokens<double>, or any other type you care to invent in future that has a stream extraction operator (and whose string representation doesn't contain spaces, or whatever else it is you use to delimit items in your text file).
This only applies if the means of splitting up the file into tokens/items is the same regardless of the type that they're going to be read as. The reason I say "maybe" is that it might be better to first read the file into strings in a non-template function, then have a separate template function that tries to convert them to int/double/whatever, filtering out the ones that fail to convert. You'll note that the above code isn't terribly efficient with T = string, and frankly having written it you're unlikely to test it with any types other than the two you're currently interested in (int and string), so you could be storing up trouble for later.
I've made a second change to your function interface, which is to write the results to an iterator rather than returning a vector by value. This is an independent change, but it's a common trick with template functions because it means the caller can have the results written to a vector, or any other container they prefer, or perhaps process them without storing them all at once (for example if all that's needed is to write them to a stream). To get the original behavior, with the results in a vector, you'd call it like this:
std::vector<int> v;
readTokens<int>(std::back_inserter(v));
Templates would make no sense here, because the code for the function (presumably) depends on its argument type. So you would have to specialise the template anyway, and you might as well just use overloading for this.