Consider this simple code snippet:
static void Foo(std::string&& arg) {
printf("(universal reference) = %s\n", arg.c_str());
}
static void Foo(const std::string&& arg) {
printf("(const universal reference) = %s\n", arg.c_str());
}
static void Foo(std::string& arg) {
printf("(reference) = %s\n", arg.c_str());
}
static void Foo(const std::string& arg) {
printf("(const reference) = %s\n", arg.c_str());
}
int main(int argc, const char * argv[]) {
std::string value{"value"};
const std::string const_value{"const_value"};
Foo(value);
Foo(const_value);
Foo(std::string("temporary"));
Foo("litteral");
}
The resulting output under Clang is:
(reference) = value
(const reference) = const_value
(universal reference) = temporary
(universal reference) = literal
Why is the value case not using the universal reference version of the function? I thought one of the key benefits of universal references was that they could accept both lvalues and rvalues?
PS: It's not possible to force it either:
static void Foo(std::string&& arg) {
printf("(universal reference) = %s\n", arg.c_str());
}
//static void Foo(const std::string&& arg) {
// printf("(const universal reference) = %s\n", arg.c_str());
//}
//
//static void Foo(std::string& arg) {
// printf("(reference) = %s\n", arg.c_str());
//}
//
//static void Foo(const std::string& arg) {
// printf("(const reference) = %s\n", arg.c_str());
//}
int main(int argc, const char * argv[]) {
std::string value{"value"};
const std::string const_value{"const_value"};
Foo(value); <--- FAILS COMPILING: No matching function for call to 'Foo'
// Foo(const_value);
Foo(std::string("temporary"));
Foo("literal");
}
UPDATE: It appears "universal references" are only for templates, not regular functions, which explains why the above is not working as I was expecting.
However here's a version using a templated function:
template<typename T>
static void Foo(T&& arg) {
printf("%s\n", arg.c_str());
}
int main(int argc, const char * argv[]) {
std::string value{"value"};
const std::string const_value{"const_value"};
Foo<std::string>(value); <--- FAILS COMPILING: No matching function for call to 'Foo'
Foo<std::string>(const_value); <--- FAILS COMPILING: No matching function for call to 'Foo'
Foo<std::string>(std::string("temporary"));
Foo<std::string>("literal");
}
Why is the value case still not working through universal references (I understand why the const_value case is not)?
UPDATE: For reference, here's the final version that works with both lvalues and rvalues:
template<typename T>
static void Foo(T&& arg) {
printf("%s\n", arg.c_str());
}
int main(int argc, const char * argv[]) {
std::string value{"value"};
const std::string const_value{"const_value"};
Foo(value);
Foo(const_value);
Foo(std::string("temporary"));
//Foo("literal"); <--- Cannot work anyway since template is instantiated with arg as a const char*
}
Those are not "universal references". Those are merely rvalue references.
A "universal reference" (FYI: this term has fallen out of disfavor) refers explicitly to an rvalue reference applied directly to a fully template deduced type (as opposed to something like vector<T> &&v, which is only partially deduced) when using template argument deduction. None of your functions are template functions, so they behave like regular rvalue references.
foo(value) calls the lvalue reference version because variables passed as parameters bind to lvalue reference parameter types.
However here's a version using a templated function:
None of those functions use template argument deduction. You're explicitly specifying the template parameter directly, not allowing it to be deduced by the arguments you call it with.
Or more to the point:
Foo<std::string>(value);
Foo(value);
Foo<std::string>(std::string("temporary"));
Foo(std::string("temporary"));
In the first case, T is std::string, because you specified it to be so. Therefore, Foo<std::string> takes a std::string&&. value cannot bind to an rvalue reference, so it's a compile error.
In the second case, T is deduced through template argument deduction based on the argument expression. value is an lvalue, so T is deduced as std::string&. Therefore, Foo in this case takes a std::string& &&, which devolves down to std::string&.
In the third case, T is std::string. Therefore again, Foo<std::string> takes a std::string&&. A temporary can bind to an rvalue reference just fine, so it does so.
In the fourth case, T is deduced through template argument deduction based on the argument expression. The expression is a std::string temporary prvalue, so T is deduced as std::string (note the lack of references). So Foo in this case takes a std::string&&.
Related
I am trying to make an HTTP class, and I want to use C++11 (not C++14 yet) callbacks via lambdas. I have 2 mockups available, the first one works... but looks ugly. The second one I am aiming, is not compiling (error at the end).
I cannot use std::function, as this is an embedded project, and that template generates a lot of code.
#include <cstring>
class HTTP
{
public:
void get1(const char* url, void* context, void (*callback)(void*, const char*) )
{
callback(context, "");
}
void get2(const char* url, void (*callback)(const char*) )
{
callback("");
}
};
void test()
{
int k;
HTTP http;
http.get1( "http://google.com", &k, [](void* context, const char* s){
int *k = (int*) context;
*k = strlen(s);
});
// this does not compile, looking for other alternatives
http.get2( "http://google.com", [&k](const char* s){
k = strlen(s);
});
}
Error from gcc (xtensa-esp32-elf-g++ (crosstool-NG crosstool-ng-1.22.0-80-g6c4433a) 5.2.0)
HttpRequests.cpp: In function 'void test()':
HttpRequests.cpp:29:6: error: no matching function for call to 'HTTP::get2(const char [18], test()::<lambda(const char*)>)'
});
^
HttpRequests.cpp:11:10: note: candidate: void HTTP::get2(const char*, void (*)(const char*))
void get2(const char* url, void (*callback)(const char*) )
^
HttpRequests.cpp:11:10: note: no known conversion for argument 2 from 'test()::<lambda(const char*)>' to 'void (*)(const char*)'
Lambdas without a capture list are compatible with function pointers, so your first lambda can be passed as an argument to get1(). However, lambdas with a capture list are not convertible to function pointers so it can not be passed to get2().
Lambdas with captures have state but functions can not have state, which is why such lambdas are not convertible to function pointers.
The most common way to have a function accept any lambda (or any callable object) is to use function templates:
class HTTP {
// ...
template <typename Callable>
void get1(const char* url, void* context, Callable callback)
{
callback(context, "");
}
template <typename Callable>
void get2(const char* url, Callable callback)
{
callback("");
}
}
Being function templates, code size might become an issue. If that's not acceptable, then keep your current functions and restrict yourself to never passing lambdas that use captures.
I have a structure that should be statically initialized.
struct Option
{ char Option[8];
void (*Handler)(const char* value);
};
void ParseInto(const char* value, const char** target); // string option
void ParseInto(const char* value, int* target, int min, int max); // int option
static int count = 1;
static const char* name;
static const Option OptionMap[] =
{ { "count", [](const char* value) { ParseInto(value, &count, 1, 100); } }
, { "name", [](const char* value) { ParseInto(value, &name); } }
// ...
};
Up to this point it works.
To get rid of repeating the lambda function definition over and over (there are dozens) I want to use a factory like this:
struct Option
{ const char Option[8];
const void (*Handler)(const char* value);
template<typename ...A>
Option(const char (&option)[8], A... args)
: Option(option)
, Handler([args...](const char* value) { ParseInto(value, args...); })
{}
};
static const Option OptionMap[] =
{ { "count", &count, 1, 100 }
, { "name", &name }
};
This does not work for two reasons:
I did not find a type for the first constructor parameter option that perfectly forwards the initialization of the character array. The difficult part is that the length of the assigned array does not match the array length in general.
The even harder part is that the lambda function has a closure and therefore cannot decay to a function pointer. But all parameters are compile time constants. So It should be possible to make the constructor constexpr. However, lambdas seem not to support constexpr at all.
Anyone an idea how to solve this challenge?
The current work around is a variadic macro. Not that pretty, but of course, it works.
Context is C++11. I would not like to upgrade for now, but nevertheless a solution with a newer standard would be appreciated. Problems like this tend to reappear from time to time.
There are some further restrictions by the underlying (old) code. struct Option must be a POD type and the first member must be the character array so a cast from Option* to const char* is valid.
The minimal code below gives me a compile error:
#include <iostream>
#include <functional>
using namespace std;
template<typename ActionType, typename... Cols>
void print_action(function<ActionType*(Cols..., ActionType)> action_factory)
{
}
int main(int argc, char *argv[])
{
print_action<string, uint8_t>(function<string*(uint8_t, string)>());
return 0;
}
The error is:
foo.cc: In function ‘int main(int, char**)’:
foo.cc:13:69: error: no matching function for call to ‘print_action(std::function<std::basic_string<char>*(unsigned char, std::basic_string<char>)>)’
print_action<string, uint8_t>(function<string*(uint8_t, string)>());
^
foo.cc:13:69: note: candidate is:
foo.cc:7:6: note: template<class ActionType, class ... Cols> void print_action(std::function<ActionType*(Cols ..., ActionType)>)
void print_action(function<ActionType*(Cols..., ActionType)> action_factory)
^
foo.cc:7:6: note: template argument deduction/substitution failed:
foo.cc:13:69: note: mismatched types ‘std::basic_string<char>’ and ‘unsigned char’
print_action<string, uint8_t>(function<string*(uint8_t, string)>());
^
foo.cc:13:69: note: ‘std::function<std::basic_string<char>*(unsigned char, std::basic_string<char>)>’ is not derived from ‘std::function<std::basic_string<char>*(Cols ..., std::basic_string<char>)>’
I also try to change the input parameter to a simple pointer function by below code:
#include <iostream>
#include <functional>
using namespace std;
template<typename ActionType, typename... Cols>
void print_action(ActionType*(*action_factory)(Cols..., ActionType))
{
}
string* foo_factory(uint8_t cols, string act)
{
}
int main(int argc, char *argv[])
{
print_action<string, uint8_t>(foo_factory);
return 0;
}
It gives me the same error. After some works my last guess is that it is a bug of g++ because if I change the variadic template parameter to a simple parameter no errors happen.
Am I right or I missed some syntax of c++?
I use g++-4.8.4 with c++11 flag(I checked it using clang-3.4 and g++-4.9.2).
EDIT:
If I change the code to this:
#include <iostream>
#include <functional>
using namespace std;
template<typename ActionType, typename... Cols>
struct Foo
{
Foo()
{}
void print_action(function<ActionType*(Cols..., ActionType)> action_factory)
{
}
};
int main(int argc, char *argv[])
{
Foo<string, uint8_t> f;
f.print_action(function<string*(uint8_t, string)>());
return 0;
}
I get no error. I don`t understand this behavior because in both situations I defined the template parameters explicitly and I did not expect any deduction, but It seems that compiler does some deduction when it is a template function but not when it is a member function of a template class.
The issue is that you have (Cols..., ActionType). One might think that the compiler should notice that Cols... should be all the arguments before the end so long as the end is the same as ActionType, but this is not how the language works.
A simple solution would to just deduce the entire argument list. Compilation will fail anyway if you happen to use the final argument as in a way the type doesn't support, and you could always add in a static_assert to ensure that the final parameter is the same as ActionType if you really wanted.
template<typename ActionType, typename... Cols>
void print_action(function<ActionType*(Cols...)> action_factory)
{
//Maybe with a static_assert like this
using LastArg = typename std::tuple_element<
sizeof...(Cols)-1, //number of args - 1
std::tuple<Cols...>
>::type;
static_assert(std::is_same<LastArg, ActionType>::value,
"The final argument must be the same type as ActionType");
}
Live Demo
Usually variadic templates are written thus
template<typename First, typename... Rest> class test;
The compiler matches the first argument and leaves the rest (empty or more) to variadic part. The behaviour when reversed is not as expected. Variadic template arguments are greedy, in that, all arguments are eaten-up by it, leaving none to the last.
Your example code compiles fine, when the order is reversed:
template<typename ActionType, typename... Cols>
void print_action(function<ActionType*(ActionType, Cols...)>) {
}
int main()
{
print_action(function<string*(string, uint8_t)>());
}
Live example.
There's a difference between argument type deduction and instantiation. Quote from C++ Templates: The Complete Guide:
The process of replacing template parameters by concrete types is called instantiation. It results in an instance of a template.
When a function template is instantiated, we get a function out of it; same for class/struct.
It seems that compiler does some deduction when it is a template function but not when it is a member function of a template class.
There is no type deduction or instantiation happening for the function call. It is not a function template, but just a function. The call is just another ordinary function call.
However, the struct is really a struct template and a struct is created out of the template, when an object was created. For this struct template instantiation
template<typename ActionType, typename... Cols>
struct Foo;
the order is correct (the variadic argument is the last) and so it works.
Follwing short programm will run perfect with VS 2013 and reach the marked point. But in XCode the compiler will show an error due ambiguous constructor. How to work around?
#include <iostream>
#include <string>
class atest
{
public:
explicit operator const char *()
{
return "";
}
template<class T> operator T()
{
}
operator std::string()
{
return std::string("Huhuhu");
}
template<class T> atest &operator =(T value)
{
}
atest &operator =(const std::string &value)
{
return *this; // I want to reach this point
}
};
int main(int argc, char* argv[])
{
atest tst;
// auto a = (std::string)tst;
std::string astr;
// do some stuff
astr=tst; // I wanna keep this line
return 0;
}
Clang is not able to distinguish between different constructor where VS2013 is taking the right one. I search now for a way to exclude the "const char *" template of the assignment operator.
std::string have multiple constructors taking single arguments, and since you provide both a conversion operator for std::string and a generic any-type conversion operator, the compiler simply don't know which constructor to pick.
I think you have written far too many overloaded functions. The only function you need is this:
operator std::string()
{
return std::string("Huhuhu");
}
Comment rest all and your code would work just fine.
Suppose you want to avoid narrowing when calling a function
void foo(char c) { /* ... */ }
foo(4); // get a compilation error here
You can define your target function, and a forwarding template overload that will attempt a non-narrowing conversion to the target type (DEMO):
void foo(char) {}
template <typename T>
void foo(T&& t) { foo(char{std::forward<T>(t)}); }
foo('a');
// foo(4); // ill-formed
foo({4});
// foo(0); // ill-formed
foo({0});
// foo(u'a'); // ill-formed
foo({u'a'});
int i = 2;
// foo(i); // ill-formed
// foo({i}); // ill-formed
This has the nice advantage that clients can force the conversion themselves by passing a braced-init-list. Since the braced-init-list impedes template deduction, only the target function can be selected by overload resolution. So even though e.g. foo(4) matches the template overload and is ill-formed - since int cannot in general be converted to char without narrowing - foo({4}) is well-formed since 4 can be converted to char without narrowing.
You can use a class template on T that has
1) a template constructor on a different type X that tries to instantiate the class when the parameter is not T
2) a constructor with T as param that takes care of the case where you are instantiating the class with the exact type
#include <iostream>
// g++-4.9 -Werror=narrowing -std=c++11 main2.cc
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55783
template <typename T>
struct no_narrowing
{
using type = T;
// this template constructor lets you try to
// instantiate a no_narrowing using a different
// type. if Narrowing would take place
// value{ val } takes care of it
template <typename X>
no_narrowing(X val) : value{val} {}
// if type is exactly T we use this
no_narrowing(type val) : value{val} {}
operator type() const { return value;}
type value;
};
template <typename T>
using nn = no_narrowing<T>;
void print(nn<char> v)
{
std::cout << v << std::endl;
}
int main(int argc, char *argv[])
{
int i = 2;
print('d');
print(i); // this will not compile
return 0;
}