Is there a non-boost way to create a function with variable arguments? I know the argument types number of arguments and they are usually less then 5, all of the same type.
I need to know if there is a way without supplying the argument count or ending the param list with null.
I know the argument types and they are usually less then 5.
If it is not going to be greater than 5, then simple overloads may do the work. Call the overload which accepts maximam number of arguments from all other overloads accepting less than 5 arguments, or define a worker (internal) function, call this from the overloads.
If possible, you could use default values for some of the parameters, if that helps reducing the number of overloaded functions.
In C++11, you could use variadic-template.
For up to 5 arguments all of the same type, simple overloads can do the trick.
For more generality, supporting any number of arguments of the same type, just pass a collection such as a std::vector.
For a C++03 technique to build such a collection on the fly in each call, see my other answer; for C++11, if you do not need to support Visual C++ you can use curly braces initializer lists as actual arguments.
Is cstdarg what you are looking for? This is the standard C++ way to generate functions with variable numbers of arguments.
You should be able achieve passing variable arguments using va_list.
You can:
if you're using C++11 you can use variadic templates, otherwise...
provide overloads
use arguments which default to some sentinel values you can recognise ala f(const T& v1 = missing, const T& v2 = missing, ...) { if (v5 != missing) ...
create a simple helper template that can optionally be constructed from the data type and has a bool to track whether it was
you may need to support types without default constructors by either using new/delete (simple and safe but slow) or having an aligned buffer you placement new into, manually destroy etc. (fiddly and easier to get wrong but faster)
some compilers have variadic macro support
if you're prepared to change the calling syntax a bit, you can use any number of things:
accept a vector (using a union or variant if the types differ)
accept an array (possibly using the template <size_t N> void f(T (&data)[N]) { ... } trick to have the compiler provide the array size to you automatically)
some kind of lhs object to which extra values can be supplied using an operator such as operator, or operator<<
As a general C++03 solution you can provide a setter that returns a reference to the object that it's called on, so that it can be called again. And again. And so on, called chaining.
It's the same scheme as iostreams use for operator<<.
E.g.
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
void foo( char const s[] )
{
cout << s << endl;
}
class StringBuilder
{
private:
string s_;
template< class Type >
string fastStringFrom( Type const& v )
{
stringstream stream;
stream << v;
return stream.str();
}
char const* fastStringFrom( char const* s )
{
return s;
}
string const& fastStringFrom( string const& s )
{
return s;
}
public:
template< class Type >
StringBuilder& operator<<( Type const& v )
{
s_ += fastStringFrom( v );
return *this; // Supports chaining.
}
operator string const& () const { return s_; }
operator char const* () const { return s_.c_str(); }
};
int main()
{
typedef StringBuilder S;
foo( S() << "6*7 = " << 6*7 << "." ); // Any number of arguments.
}
Instead of converting the argument values to text, you just do whatever it is that you need. For example, with a fixed set of possible types you can store the arguments in a collection.
If you do not need to support the Visual C++ compiler, then alternatively you can use a C++11 variadic template.
Related
I have a class that has both implicit conversion operator() to intrinsic types and the ability to access by a string index operator[] that is used for a settings store. It compiles and works very well in unit tests on gcc 6.3 & MSVC however the class causes some ambiguity warnings on intellisense and clang which is not acceptable for use.
Super slimmed down version:
https://onlinegdb.com/rJ-q7svG8
#include <memory>
#include <unordered_map>
#include <string>
struct Setting
{
int data; // this in reality is a Variant of intrinsic types + std::string
std::unordered_map<std::string, std::shared_ptr<Setting>> children;
template<typename T>
operator T()
{
return data;
}
template<typename T>
Setting & operator=(T val)
{
data = val;
return *this;
}
Setting & operator[](const std::string key)
{
if(children.count(key))
return *(children[key]);
else
{
children[key] = std::shared_ptr<Setting>(new Setting());
return *(children[key]);
}
}
};
Usage:
Setting data;
data["TestNode"] = 4;
data["TestNode"]["SubValue"] = 55;
int x = data["TestNode"];
int y = data["TestNode"]["SubValue"];
std::cout << x <<std::endl;
std::cout << y;
output:
4
55
Error message is as follows:
more than one operator "[]" matches these operands:
built-in operator "integer[pointer-to-object]" function
"Setting::operator[](std::string key)"
operand types are: Setting [ const char [15] ]
I understand why the error/warning exists as it's from the ability to reverse the indexer on an array with the array itself (which by itself is extremely bizarre syntax but makes logical sense with pointer arithmetic).
char* a = "asdf";
char b = a[5];
char c = 5[a];
b == c
I am not sure how to avoid the error message it's presenting while keeping with what I want to accomplish. (implicit assignment & index by string)
Is that possible?
Note: I cannot use C++ features above 11.
The issue is the user-defined implicit conversion function template.
template<typename T>
operator T()
{
return data;
}
When the compiler considers the expression data["TestNode"], some implicit conversions need to take place. The compiler has two options:
Convert the const char [9] to a const std::string and call Setting &Setting::operator[](const std::string)
Convert the Setting to an int and call const char *operator[](int, const char *)
Both options involve an implicit conversion so the compiler can't decide which one is better. The compiler says that the call is ambiguous.
There a few ways to get around this.
Option 1
Eliminate the implicit conversion from const char [9] to std::string. You can do this by making Setting::operator[] a template that accepts a reference to an array of characters (a reference to a string literal).
template <size_t Size>
Setting &operator[](const char (&key)[Size]);
Option 2
Eliminate the implicit conversion from Setting to int. You can do this by marking the user-defined conversion as explicit.
template <typename T>
explicit operator T() const;
This will require you to update the calling code to use direct initialization instead of copy initialization.
int x{data["TestNode"]};
Option 3
Eliminate the implicit conversion from Setting to int. Another way to do this is by removing the user-defined conversion entirely and using a function.
template <typename T>
T get() const;
Obviously, this will also require you to update the calling code.
int x = data["TestNode"].get<int>();
Some other notes
Some things I noticed about the code is that you didn't mark the user-defined conversion as const. If a member function does not modify the object, you should mark it as const to be able to use that function on a constant object. So put const after the parameter list:
template<typename T>
operator T() const {
return data;
}
Another thing I noticed was this:
std::shared_ptr<Setting>(new Setting())
Here you're mentioning Setting twice and doing two memory allocations when you could be doing one. It is preferable for code cleanliness and performance to do this instead:
std::make_shared<Setting>()
One more thing, I don't know enough about your design to make this decision myself but do you really need to use std::shared_ptr? I don't remember the last time I used std::shared_ptr as std::unique_ptr is much more efficient and seems to be enough in most situations. And really, do you need a pointer at all? Is there any reason for using std::shared_ptr<Setting> or std::unique_ptr<Setting> over Setting? Just something to think about.
I have a function whose signature is:
void func(std::optional<std::string> os = std::nullopt);
(I’m aliasing std::experimental::optional until std::optional is officially available.)
However, I’m having difficulty calling it cleanly. The compiler will refuse to perform two implicit conversions (const char* ➝ std::string ➝ std::optional<std::string>) to call it with a raw C-string literal. I can do this:
func(std::string("Hello"));
And the compiler will figure that a std::optional is needed, and do the conversion. However, this is way too verbose. Thanks to C++11, I can also do this:
func({"Hello"});
While this is way better, it's still not ideal. I'd like to be able to call this function like any other that takes a std::string. Is this possible? Making the function take another parameter type is okay, as long as it behaves similarly to/is directly convertible to std::optional. Thanks.
C++14 adds a bunch of user-defined literals to the standard library in order to make code less verbose. It looks something like this:
using namespace std::string_literals; // needed
// using namespace std::literals; // also ok, but unnecessary
// using namespace std::literals::string_literals; // also ok, but why??
int main()
{
std::string str = "string"s;
^^^^^^^^
// This is a std::string literal,
// so std::string's copy constructor is called in this case
}
Also take a look at this and this for reference.
You can do that with a bit of templates and sfinae:
template<typename T, std::enable_if_t<
std::is_constructible<std::string, T>::value &&
!std::is_constructible<std::optional<std::string>, T>::value>* = nullptr>
void func(T&& s) {
void func(std::string(std::forward<T>(s)));
}
This overload will be picked when a string would be constructible with a forwarded T but only when std::optional<std::string> is not constructible.
You function will be callable with any object that a string can be constructed with:
func("potato"); // working, forward the string literal to a std::string
I have seen people write (on stack overflow itself, asking some even advanced concepts) something along the lines of:
template<typename... args>
std::tuple<args...> parse(istream stream)
{
return std::make_tuple(args(stream)...);
}
and use it as
auto tup = parse<int, float, char>(stream);
How does the above code construct the tuple by parsing the stream? Is there any specific requirement on how data is to be put into the stream?
For this to work there must be an implicit conversion from std::istream to all the types specified as template arguments.
struct A {
A(std::istream&) {} // A can be constructed from 'std::istream'.
};
struct B {
B(std::istream&) {} // B can be constructed from 'std::istream'.
};
int main() {
std::istringstream stream{"t1 t2"};
auto tup = parse<A, B>(stream);
}
It works by expanding the variadic list of types and constructs each type with the supplied std::istream as argument. It is then left to the constructor of each type to read from the stream.
Also be aware that the evaluation order of the constructors is not specified so you can't expect that the first type in the variadic list will read from the stream first etc.
The code as it is does not work with built in types as int, float and char as there is no conversion from std::istream to any of those types.
It works poorly. It relies on the target type having a constructor that takes an std::istream.
As many types don't have this, and you cannot add it to something like int, this is a bad plan.
Instead do this:
template<class T>
auto read_from_stream( std::istream& stream, T* unused_type_tag )
-> typename std::decay<decltype( T{stream} )>::type
{
return {stream};
}
template<class T>
auto read_from_stream( std::istream& stream, T* unused_type_tag, ... )
-> typename std::decay<decltype( T(stream) )>::type
{
return T(stream);
}
template<typename... args>
std::tuple<args...> parse(std::istream& stream) {
return std::tuple<args...>{
read_from_stream(stream, (args*)nullptr)...
};
}
now instead of directly constructing the arguments, we call read_from_stream.
read_from_stream has two overloads above. The first tries to directly and implicitly construct our object from an istream. The second explicitly constructs our object from an istream, then uses RVO to return it. The ... ensures that the 2nd one is only used if the 1st one fails.
In any case, this opens up a point of customization. In the namespace of a type X we can write a read_from_stream( std::istream&, X* ) function, and it will automatically be called instead of the default implementation above. We can also write read_from_stream( std::istream&, int* ) (etc) which can know how to parse integers from an istream.
This kind of point of customization can also be done using a traits class, but doing it with overloads has a number of advantages: you can inject the customizations adjacent to the type, instead of having to open a completely different namespace. The custom action is also shorter (no class wrapping noise).
I currently have a map<int, std::wstring>, but for flexibility, I want to be able to assign a lambda expression, returning std::wstring as value in the map.
So I created this template class:
template <typename T>
class ValueOrFunction
{
private:
std::function<T()> m_func;
public:
ValueOrFunction() : m_func(std::function<T()>()) {}
ValueOrFunction(std::function<T()> func) : m_func(func) {}
T operator()() { return m_func(); }
ValueOrFunction& operator= (const T& other)
{
m_func = [other]() -> T { return other; };
return *this;
}
};
and use it like:
typedef ValueOrFunction<std::wstring> ConfigurationValue;
std::map<int, ConfigurationValue> mymap;
mymap[123] = ConfigurationValue([]() -> std::wstring { return L"test"; });
mymap[124] = L"blablabla";
std::wcout << mymap[123]().c_str() << std::endl; // outputs "test"
std::wcout << mymap[124]().c_str() << std::endl; // outputs "blablabla"
Now, I don't want to use the constructor for wrapping the lambda, so I decided to add a second assignment operator, this time for the std::function:
ValueOrFunction& operator= (const std::function<T()>& other)
{
m_func = other;
return *this;
}
This is the point where the compiler starts complaining. The line mymap[124] = L"blablabla"; suddenly results in this error:
error C2593: 'operator = is ambiguous'
IntelliSense gives some more info:
more than one operator "=" matches these operands: function
"ValueOrFunction::operator=(const std::function &other) [with
T=std::wstring]" function "ValueOrFunction::operator=(const T
&other) [with T=std::wstring]" operand types are: ConfigurationValue =
const wchar_t
[10] c:\projects\beta\CppTest\CppTest\CppTest.cpp 37 13 CppTest
So, my question is, why isn't the compiler able to distinguish between std::function<T()> and T? And how can I fix this?
The basic problem is that std::function has a greedy implicit constructor that will attempt to convert anything, and only fail to compile in the body. So if you want to overload with it, either no conversion to the alternative can be allowed, of you need to disable stuff that can convert to the alternative from calling the std::function overload.
The easiest technique would be tag dispatching. Make an operator= that is greedy and set up for perfect forwarding, then manually dispatch to an assign method with a tag:
template<typename U>
void operator=(U&&u){
assign(std::forward<U>(u), std::is_convertible<U, std::wstring>());
}
void assign(std::wstring, std::true_type /*assign_to_string*/);
void assign(std::function<blah>, std::false_type /*assign_to_non_string*/);
basically we are doing manual overload resolution.
More advanced techniques: (probably not needed)
Another approach would be to limit the std::function = with SFINAE on the argument being invoked is valid, but that is messier.
If you have multiple different types competing with your std::function you have to sadly manually dispatch all of them. The way to fix that is to test if your type U is callable with nothing and the result convertible to T, then tag dispatch on that. Stick the non-std::function overloads in the alternative branch, and let usual more traditional overloading to occur for everything else.
There is a subtle difference in that a type convertible to both std::wstring and callable returning something convertible to T ends up being dispatched to different overloads than the original simple solution above, because the tests used are not actually mutually exclusive. For full manual emulation of C++ overloading (corrected for std::functions stupidity) you need to make that case ambiguous!
The last advanced thing to do would be to use auto and trailing return types to improve the ability of other code to detect if your = is valid. Personally, I would not do this before C++14 except under duress, unless I was writing some serious library code.
Both std::function and std::wstring have conversion operators that could take the literal wide string you are passing. In both cases the conversions are user defined and thus the conversion sequence takes the same precedence, causing the ambiguity. This is the root cause of the error.
Suppose I have a class X:
class X {
// ...
size_t hash() const { return ...; }
};
I would like to create a std::tr1::unordered_map<X, int, HashFn> where I want to pass in
X::hash() as HashFn. I know I can declare my own functor object. I feel that
there should be a way to do this by directly passing a pointer to X::hash().
Is there?
No; as you've shown it, you need a small utility struct:
#include <functional>
template<typename T, std::size_t (T::*HashFunc)() const = &T::hash>
struct hasher : std::unary_function<T, std::size_t>
{
std::size_t operator ()(T const& t) const
{
return (t.*HashFunc)();
}
};
Then you can create an unordered_map like so:
std::tr1::unordered_map<X, int, hasher<X> > m;
No, there isn't. The reason is that whatever is used as your HashFn must take a single argument which is a const reference to an object in the container. X::hash takes a single argument which is a const pointer to an object in the container (the this pointer is an implicit first argument in this case), so using that function by it self is not possible.
You probably use some bind magic, using boost::lambda and boost::bind. I'm not exactly sure how, but it would probably look something like this:
boost::bind(&X::hash, &_1);
Which creates a function object which will call X::hash with a pointer.
size_t hash() const { return ...;}
A function which calculates hash value takes one parameter of type Key which your function doesn't take. Hence its signature is wrong to begin with.
Since you want to implement a function, rather than a functor, here is how it should be done:
size_t hash(const KeyType &key)
{
return /*calculate hash and return it*/;
}
Make it static member function and pass it as X::hash or make it a free function, is your choice.
You can't directly, but you can wrap it. The easy way to do so is to use boost::mem_fn(), or the standard equivalents if your compiler supports them: tr1::mem_fn() (from TR1) or std::mem_fn() (from C++11).
EDIT: Actually it's not so simple. mem_fn() will work fine for a function parameter, but since its return type is unspecified it's difficult to use as a template parameter. If you have C++11 support you could use decltype to find the type; otherwise you're probably best off writing your own function object as you mentioned.