How do I avoid the extra copy in the generic function template? - c++

Background
I have some generic code for persistence that uses boost::variant to store multiple types. While outputting values, I had to write a converter function protected_backslash_n, which does nothing, in the default case, but return the same value back.
In the specialised case where the template parameter is a std::string I use boost::regex_replace() to search for \n and replace it with \\n.
Question
The code works fine, but it would be nice if I could get rid of the extra copy in the generic case, due to the return-by-value.
Is there a way to do this while allowing the specialised std::string version to work fine?
I tried changing the return value to T const&, but then the specialised version won't match up.
Error
GetPipedValues.hpp:15:21: error: template-id ‘protect_backslash_n<std::string>’ for ‘std::string pitbull::protect_backslash_n(const string&)’ does not match any template declaration
Code
template<typename T>
inline T protect_backslash_n( T const& orig )
{
return orig; // BAD: extra copy - how do I get rid of this?
}
template<>
inline std::string protect_backslash_n<std::string>( std::string const& orig )
{
boost::regex expr("(\\n)");
std::string fmt("(\\\\n)");
return boost::regex_replace(
orig, expr, fmt, boost::match_default | boost::format_all
);
}

Don't make it a template, but just an overload. The compiler will choose that function over a template instantiation, if the parameter matches.
std::string protect_backslash_n( std::string const& orig);

That should be simple:
template <typename T>
T const& protect_backslash_n(T const& orig)
{
return orig;
}
And the std::string version as you had it. Maybe you will need additional overloads, e.g. taking a nonconst reference. In C++11 that function should mimic std::forward<T> in the default case.

Related

Passing object of struct template as a function parameter

I'm trying to create a function which takes an object of my struct template as an argument.
template <unsigned dim>
struct vec{
float d[dim];
template<typename ...T>
vec(T&&... args) : d{args...}{}
float operator[] (unsigned n) const { return d[n]; }
// ...
};
This code works fine on its own, but it starts to hassle when I want to create a function which takes an "vec" object as a parameter.
void asdf(vec<3> a){ ... }
When I create an instance of my struct as the parameter input it works fine:
asdf(vec<3>{5.f, 10.f, 3.f}); // Works fine
But when I try something like this my compiler won't buy it:
vec<3> test{5.f, 10.f, 3.f};
asdf(test); // error: cannot convert 'vec<3>' to 'float' in initialization
My IDE says the problem is in the constructor. Any help would be greatly appreciated!
You need to exclude the constructor template from overload set when being passed a vec. Otherwise it's an exact match and preferred over the copy constructor which takes a const vec& (then requires to add constness to be called).
E.g.
template<typename T1, typename ...T, typename std::enable_if_t<!std::is_same_v<std::decay_t<T1>, vec>>* = nullptr>
vec(T1&& t, T&&... args) : d{std::forward<T1>(t), std::forward<T>(args)...}{}
As #NathanOliver suggested you might need to define the default constructor if you use the constructor template as the default constructor.
Overload resolution is tricky. A perfect match will be chosen before one that requires a conversion.
This template constructor is a perfect match for anything:
template<typename ...T> vec(T&&... args);
This copy constructor is a perfect match for const vec types, and in that case is a better match than the template (because all things equal, a non-template function is defined to be a better match.)
vec(vec const& other); // copy constructor
In your code, the copy constructor is implicitly declared by the compiler.
Now, when you do this:
vec<3> test{5.f, 10.f, 3.f};
asdf(test); // error
The problem is that you are creating a non-const "test" object, so overload resolution finds a perfect match with the templated constructor, but must do a "const conversion" to match the copy constructor (and the copy constructor is what you want to use.) Therefore, it selects the template function and fails.
However, if you declare test as a const object, it will compile and work as you probably expect:
vec<3> const test{5.f, 10.f, 3.f}; // **** Notice, const now
asdf(test); // ok
What you really want to do is prevent the template constructor from dominating the copy constructor, even for const conversions, and that can be done in multiple ways.
add constraints to the constructor to prevent it from matching vec objects
overload the copy constructor with const and non-const versions
In c++20 the first approach is straight-forward. Just add a requires clause to ensure that none of your arguments are of type vec:
template<typename ...T>
vec(T&&... args) requires (not (std::is_same_v<T, vec> && ...))
: d{args...}{}
std::enable_if is another approach on older compilers or langauge levels.
Another way you can accomplish it is to have "two" copy constructors:
vec(vec const&) = default;
vec(vec & other) = default;
This covers both cases of const and non-const vec arguments. Being non-templates, when passing a vec, one of them will match better than the template and every other type will still select the template.
It will still fail if you mix different sized vecs, though, but you probably don't want that anyway. But if you do, you can add another template specifically for it:
// Only used when Size does not match "our size"
template<auto Size>
vec(vec<Size> const & other) {
}
Your issue here is that your
template<typename ...T>
vec(T&&... args) : d{args...}{}
is greedy and will be used in place of the built in copy constructor since T&& will resolve to a better match. To fix this, you just need to add a copy constructor that is a better match then your template, and you can do that by adding
vec(vec&) = default; // for lvalues
vec(const vec&) = default; // for const lvalues
vec(vec&&) = default; // for rvalues
to you class which you can see working in this live example.

c++ template parameter compiler can not deduce

here is function to register.
template <typename ReqT, typename RespT>
bool RegisterCmdHandler(int cmd_id, std::function<int(int, const ReqT&, RespT&)> sync_handler) {
// ... do something with sync_handler and register it for later callback
return true;
}
and a specific handler to register:
int SomeHandler(int id, const Foo& req, Bar& resp) {
// ... specific logic
}
now I want to apply the Handler to Register Function, compiler complains
RegisterCmdHandler(1, SomeHandler); // ERROR, compiler can not deduce
while specificly write out the type is OK:
RegisterCmdHandler<Foo, Bar>(1, SomeHandler); // OK, compiler can deduce
but the latter has ugly API. How can I get the first on work?
How can I get the first on work?
Add an overload for plain function pointers:
template <typename ReqT, typename RespT>
bool RegisterCmdHandler(int cmd_id, int(*sync_handler)(int, const ReqT&, RespT&)) {
std::function<int(int, const ReqT&, RespT&)> sync_handler2(sync_handler);
return RegisterCmdHandler(cmd_id, sync_handler2);
}
How can I get the first on work?
I see some ways.
(1) If you can modify the RegisterCmdHandler() function and you don't need to know, inside it, what types ReqT and RestT are, I suggest you to avoid at all std::function and accept sync_handler as a simple template type.
I mean
template <typename F>
bool RegisterCmdHandler (int cmd_id, F sync_handler) {
// ... do something with sync_handler
return true;
}
This is a very flexible solution because F can be a function, a function pointer, a std::function, a lambda (also a generic lambda, so this solution is more flexible than using std::function), another type of class/struct with an operator(), a value returned from a std::bind. In short: a generic callable.
(2) If you can modify the RegisterCmdHandler() function but you need to know (and use) the ReqT and RestT, you can follows the plain function pointer way (see Maxim Egorushkin's answer for the syntax). Unfortunately this works with function pointers only and doesn't works (by example) when sync_handler is a lambda.
(3) If you can't modify RegisterCmdHandler() but you can use C++17, you can use std::function deduction guides and call the function as follows
RegisterCmdHandler(1, std::function{SomeHandler});
or, maybe better if you have to call it in different places, call it through a converter
template <typename F>
auto CallRegisterCH (int cmd_if, F && func)
{ return RegisterCmdHandler(cmd_if, std::function{std::forward<F>(func)}); }
calling it as follows
CallRegisterCH(1, SomeHandler);
(4) if you can't modify RegisterCmdHandler() and you have to use C++11 or C++14... well... explicating the template types
RegisterCmdHandler<Foo, Bar>(1, SomeHandler);
seems to me the better way.
Other ways you can explicit the std::function
std::function<int(int, Foo const &, Bar &)> sh{ SomeHandler };
RegisterCmdHandler(1, sh);
but seems to me almost the same thing.

Tuple and variadic templates, how does this work?

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).

std::function as template parameter

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.

Variable arguments

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.