Take this example:
#include <vector>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cmath>
void PrintVec(const std::vector<float>&);
int main(int argc, char * argv[]){
float vals[] = {-1.2,0.0,1.2};
std::vector<float> test(vals, vals + sizeof(vals) / sizeof(float));
std::vector<float> absTest(3);
std::transform(test.begin(), test.end(), absTest.begin(), std::abs<float>());
PrintVec(test);
PrintVec(absTest);
return 0;
}
void PrintVec(const std::vector<float> &vec){
for (unsigned int i = 0; i < vec.size(); ++i){
std::cout << vec[i] << '\n';
}
return;
}
Using both gcc 4.3.4 and VS 2013 I get compiler errors. For gcc its:
testTransformAbs.cpp:15: error: expected primary-expression before 'float'
For VS 2013 its:
error C2062: type 'float' unexpected
If I remove <float> then I get this error:
testTransformAbs.cpp:15: error: no matching function for call to 'abs()'
/usr/include/stdlib.h:766: note: candidates are: int abs(int)
/usr/include/c++/4.3/cstdlib:144: note: long int std::abs(long int)
/usr/include/c++/4.3/cstdlib:175: note: long long int __gnu_cxx::abs(long long int)
/usr/include/c++/4.3/cmath:99: note: double std::abs(double)
/usr/include/c++/4.3/cmath:103: note: float std::abs(float)
/usr/include/c++/4.3/cmath:107: note: long double std::abs(long double)
I can create my own function
float MyAbs(float f){
return sqrt(f * f);
}
std::transform(test.begin(), test.end(), absTest.begin(), MyAbs);
And everything works. The reference on cplusplus.com says that the fourth input can be an UnaryOperation defined by:
Unary function that accepts one element of the type pointed to by InputIterator as argument, and returns some result value convertible to the type pointed to by OutputIterator.
This can either be a function pointer or a function object.
To me this should be able to use std::abs(). I also tried fabs with the same result. What am I missing?
std::abs is an overloaded function, not a template function. When obtaining a pointer to the function, you can choose a specific overload by casting:
std::transform(test.begin(), test.end(), absTest.begin(),
static_cast<float (*)(float)>(&std::abs));
or by using a function pointer variable:
float (*fabs)(float) = &std::abs;
std::transform(test.begin(), test.end(), absTest.begin(), fabs);
Note that I also removed the () you put after abs, since this is a function and not a class that needs to be instantiated.
std::abs is not a template. Any function in headers prefixed with a c like cmath or cstdlib do not have any C++ features like templates, because they represent the C standard library.
Also std::abs is for integral types. You should be using std::fabs for floating point types.
I dont like function pointer casts, so in cases like this one, i usually write some wrappers like these:
namespace hlp {
template <class T> struct iabs {
static_assert(std::is_integral<T>::value, "");
T operator()(T const& t){ return std::abs(t); }
};
template <class T> struct fabs {
static_assert(std::is_floating_point<T>::value, "");
T operator()(T const& t){ return std::fabs(t); }
};
}
You can use those wrappers like you wanted to use std::abs in your question.
The static_assert will generate a clean compiler error when you try to use the integral version for floating point types or vice versa.
Related
While exploring templates in C++, I stumbled upon the example in the following code:
#include <iostream>
#include <functional>
template <typename T>
void call(std::function<void(T)> f, T v)
{
f(v);
}
int main(int argc, char const *argv[])
{
auto foo = [](int i) {
std::cout << i << std::endl;
};
call(foo, 1);
return 0;
}
To compile this program, I am using the GNU C++ Compiler g++:
$ g++ --version // g++ (Ubuntu 6.5.0-1ubuntu1~16.04) 6.5.0 20181026
After compiling for C++11, I get the following error:
$ g++ -std=c++11 template_example_1.cpp -Wall
template_example_1.cpp: In function ‘int main(int, const char**)’:
template_example_1.cpp:15:16: error: no matching function for call to ‘call(main(int, const char**)::<lambda(int)>&, int)’
call(foo, 1);
^
template_example_1.cpp:5:6: note: candidate: template<class T> void call(std::function<void(T)>, T)
void call(std::function<void(T)> f, T v)
^~~~
template_example_1.cpp:5:6: note: template argument deduction/substitution failed:
template_example_1.cpp:15:16: note: ‘main(int, const char**)::<lambda(int)>’ is not derived from ‘std::function<void(T)>’
call(foo, 1);
^
(same for C++14 and C++17)
From the compiler error and notes I understand that the compiler failed to deduce the type of the lambda, since it cannot be matched against std::function.
Looking at previous questions (1, 2, 3, and 4) regarding this error, I am still confused about it.
As pointed out in answers from questions 3 and 4, this error can be fixed by explicitly specifying the template argument, like so:
int main(int argc, char const *argv[])
{
...
call<int>(foo, 1); // <-- specify template argument type
// call<double>(foo, 1) // <-- works! Why?
return 0;
}
However, when I use other types instead of int, like double, float, char, or bool, it works as well, which got me more confused.
So, my questions are as follow:
Why does it work when I explicitly specify int (and others) as the template argument?
Is there a more general way to solve this?
A std::function is not a lambda, and a lambda is not a std::function.
A lambda is an anonymous type with an operator() and some other minor utility. Your:
auto foo = [](int i) {
std::cout << i << std::endl;
};
is shorthand for
struct __anonymous__type__you__cannot__name__ {
void operator()(int i) {
std::cout << i << std::endl;
}
};
__anonymous__type__you__cannot__name__ foo;
very roughly (there are actual convert-to-function pointer and some other noise I won't cover).
But, note that it does not inherit from std::function<void(int)>.
A lambda won't deduce the template parameters of a std::function because they are unrelated types. Template type deduction is exact pattern matching against types of arguments passed and their base classes. It does not attempt to use conversion of any kind.
A std::function<R(Args...)> is a type that can store anything copyable that can be invoked with values compatible with Args... and returns something compatible with R.
So std::function<void(char)> can store anything that can be invoked with a char. As int functions can be invoked with a char, that works.
Try it:
void some_func( int x ) {
std::cout << x << "\n";
}
int main() {
some_func('a');
some_func(3.14);
}
std::function does that some conversion from its signature to the callable stored within it.
The simplest solution is:
template <class F, class T>
void call(F f, T v) {
f(v);
}
now, in extremely rare cases, you actually need the signature. You can do this in c++17:
template<class T>
void call(std::function<void(T)> f, T v) {
f(v);
}
template<class F, class T>
void call(F f_in, T v) {
std::function f = std::forward<F>(f_in);
call(std::move(f), std::forward<T>(v));
}
Finally, your call is a crippled version of std::invoke from c++17. Consider using it; if not, use backported versions.
I was trying out a sample generic function in C++ , the code follows:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
template <typename T>
T max(T a, T b){
return (a>b)?a:b;
}
int main()
{
int a=2,b=4;
float af = 2.01,bf=2.012;
double ad = 2.11,bd=1.22;
cout<<max(a,b);
}
I am getting the error as
main.cpp: In function ‘int main()’:
main.cpp:20:18: error: call of overloaded ‘max(int&, int&)’ is ambiguous
cout<<max(a,b);
^
main.cpp:20:18: note: candidates are:
main.cpp:9:3: note: T max(T, T) [with T = int]
T max(T a, T b){
^main.cpp: In function ‘int main()’:
main.cpp:20:18: error: call of overloaded ‘max(int&, int&)’ is ambiguous
cout<<max(a,b);
^
main.cpp:20:18: note: candidates are:
main.cpp:9:3: note: T max(T, T) [with T = int]
T max(T a, T b){
^main.cpp: In function ‘int main()’:
main.cpp:20:18: error: call of overloaded ‘max(int&, int&)’ is ambiguous
cout<<max(a,b);
^
main.cpp:20:18: note: candidates are:
main.cpp:9:3: note: T max(T, T) [with T = int]
T max(T a, T b){
^
What am I doing wrong here ?
What is meant by call of overloaded max(int&, int&) is ambiguous ?
Why am I getting its argument shown as & where as there was no such syntax defined by me above ?
The problem is that C++ already has a std::max definition.
Pick another name and everything should be fine.
In C++ the using namespace std approach is a bad idea as thousands of names will be injected. Just get the habit of typing std:: in front of standard names.
Remember also that saving time when writing is not really that important, what is important is saving time when reading (normally code is written just once but read and understood many times).
std:: in front of standard names actually speeds up reading and lets understanding on the spot that what is being used is part of the standard library (not everyone knows the whole standard library by heart).
Skypjack and 6502's answers are spot on so I won't go over that here.
It is also worth noting that the standard's version of max is not that clever. You can cause it not to compile with code like this:
int main()
{
int a = 0;
double b = 1;
auto c = std::max(a, b);
}
yields error message:
16 : error: no matching function for call to 'max(int&, double&)'
If we wanted to rewrite max, we might imagine that we were improving it by writing it this way:
#include <type_traits>
namespace notstd {
template <typename T1, class T2>
auto max_any(T1 a, T2 b) -> std::common_type_t<T1, T2>
{
return (a>b) ? a : b;
}
}
int main()
{
int a = 0;
double b = 1;
auto c = notstd::max_any(a, b);
}
But of course there would be some consequences.
Firstly, max_any is now forced to take copies and (possibly) perform conversions. For integers and doubles this is almost not worth mentioning.
But if T1 and T2 were two classes of object that had appropriate conversion operators, calling max_any on them could potentially be an expensive operation. It might also have material side-effects.
For this reason, std::max is defined in terms of arguments of type T&. It forces the caller to perform the conversion. It turns out that this is not a limitation of std::max. It is a safety feature.
The function does not inject any hidden side-effects into your code.
In order to maintain 'the path of least surprise' in its behaviour, the standard library sometimes requires that its users spell out the surprising behaviour that they want.
Example of surprising behaviour
This program will compile perfectly:
#include <cstdlib>
#include <iostream>
namespace notstd {
template <typename T1, class T2>
auto max_any(T1 a, T2 b)
{
return (b < a) ? a : b;
}
}
struct A {
A() = default;
};
struct B {
B() = default;
B (A const&) { std::exit(100); }
};
bool operator<(B const&, A const &) { return true; }
int main()
{
A a;
B b;
auto c = notstd::max_any(a, b);
std::cout << "Hello, World\n";
}
But it will never print "Hello, World".
Someone maintaining this code might be surprised to learn that.
There exists already a max function in the standard template library (namely std::max).
Using the using namespace directive, you are importing the names from the std:: namespace to the one in which you are using the declaration itself.
You can still use the following line to pick your implementation of max:
cout << ::max(a,b);
Otherwise, as someone already mentioned, you can choose a different name for your function or use directly the one fron the standard template library.
Is it possible in C++11 to overload const char*'s and string literals (const char[])?
The idea is to avoid having to call strlen to find the string length when this length is known already.
This snippet breaks on G++ 4.8 and Clang++ 3.2:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
template<typename T, int N>
void length(const T(&data)[N]) {
printf("%u[]\n", N - 1);
}
template<typename T>
void length(const T* data) {
printf("*%u\n", (unsigned)strlen(data));
}
int main() {
length("hello");
const char* p = "hello";
length(p);
return 0;
}
Error (Clang):
test2.cpp:16:3: error: call to 'length' is ambiguous
length("hello");
^~~~~~
test2.cpp:6:6: note: candidate function [with T = char, N = 6]
void length(const T(&data)[N]) {
^
test2.cpp:11:6: note: candidate function [with T = char]
void length(const T* data) {
^
1 error generated.
Hacked a bit, and this appears to work:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
template<typename T, int N>
void length(const T(&data)[N]) {
printf("%u[]\n", N - 1);
}
template<typename T>
void length(T&& data) {
printf("*%u\n", (unsigned)strlen(data));
}
const char *foo() {
return "bar";
}
int main() {
length("hello");
const char* p = "hello";
length(p);
length(foo());
return 0;
}
Is this valid C++11? The string literal appears to overload on T&& when the array specialization is removed. What causes this ambigousness to be resolved, but not the one in the first code snippet?
In the first case, during overload resolution you have a perfect match requiring no conversion against an array to pointer conversion (which is in the category "lvalue transformation", along with lvalue to rvalue and function to pointer conversion). A difference that is only made by an lvalue transformation is not sufficient for overload resolution to pick a winner.
In the second case, during overload resolution, both functions have the exact same parameter type. Then partial ordering as the last resort finds that the second template would accept all arguments you ever pass to it, wheras the first template only accepts arrays. Therefor the first template in the second case is found more specialized and taken.
As for your other question - no, overloading specifically for string literals is not possible. You are always going to catch arrays of the same size along with them.
I have the following code.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
template <typename Type> inline Type max(Type t1, Type t2) {
return t1 > t2 ? t1 : t2;
}
template <typename Type> inline Type max(const std::vector<Type> &vec) {
return *std::max_element(vec.begin(),vec.end());
}
template <typename Type> inline Type max(const Type *parray, int size) {
return *std::max_element(parray,parray+size);
}
int main(int argc, char *argv[]) {
std::string sarray[] = {"we","were","her","pride","of","ten"};
std::vector<std::string> svec(sarray,sarray+6);
int iarray[] = {12,70,2,169,1,5,29};
std::vector<int> ivec(iarray,iarray+7);
float farray[] = {2.5,24.8,18.7,4.1,23.9};
std::vector<float> fvec(farray,farray+5);
int imax = max(max(ivec),max(iarray,7));
float fmax = max(max(fvec),max(farray,5));
std::string smax = max(max(svec),max(sarray,6));
std::cout << "imax should be 169 -- found: " << imax << '\n'
<< "fmax should be 24.8 -- found: " << fmax << '\n'
<< "smax should be were -- found: " << smax << '\n';
return 0;
}
I am attempting to implement two simple template functions to output the max element of a vector and an array. However, I am receiving the following error when the type is a string.
error: call of overloaded 'max(std::string, std::string)' is ambiguous
Why is this occuring, and what is the best way to remedy it?
The problem is that the compiler is finding multiple matching definitions of max via ADL and it doesn't know which to choose.
Try changing the call to max to use its qualified-id:
std::string smax = ::max(max(svec),max(sarray,6));
Your code
std::string smax = max(max(svec),max(sarray,6));
translates to:
std::string smax = max(string ,string );
After max(svec) and max(sarray,6) are evaluated using your templates. Now here the problem arises:
The standard library already comes with a templated max() function. The compiler will be unable to tell whether you want your version of max() or std::max().
Now you will ask why it worked for integers and floats. Answer is in this line you are specifically mentioning std::string. Hence the compiler is getting confused.
There can be work arounds. But since you need the best solution, I would say rename your max function say MAximum.
Why is this occuring?
The compiler error already tells you why. It does not know which version of max to use.
note: candidates are:
main.cpp:6:38: note: Type max(Type, Type) [with Type = std::basic_string]
...
/usr/include/c++/4.7/bits/stl_algobase.h:210:5: note: const _Tp& std::max(const _Tp&, const _Tp&) [with _Tp = std::basic_string]
Solution:
either explicitely call your max function or just call std::max (which already exists, so why would you want to reimplement it?).
Additionally, there is one ; too much after << "fmax should be 24.8 -- found: " << fmax << '\n'
I'm trying to use an ANSI C++ for_each statement to iterate over and print the elements of a standard vector. It works if I have the for_each call a non-overloaded function, but yields a compiler error if I have it call an overloaded function.
Here's a minimal test program to show where the compiler error occurs:
#include <algorithm>
#include <iostream>
#include <vector>
struct S {
char c;
int i;
};
std::vector<S> v;
void print_struct(int idx);
void print_struct(const struct S& s);
// f: a non-overloaded version of the preceding function.
void f(const struct S& s);
int main()
{
v.push_back((struct S){'a', 1});
v.push_back((struct S){'b', 2});
v.push_back((struct S){'c', 3});
for (unsigned int i = 0; i < v.size(); ++i)
print_struct(i);
/* ERROR! */
std::for_each(v.begin(), v.end(), print_struct);
/* WORKAROUND: */
std::for_each(v.begin(), v.end(), f);
return 0;
}
// print_struct: Print a struct by its index in vector v.
void print_struct(int idx)
{
std::cout << v[idx].c << ',' << v[idx].i << '\n';
}
// print_struct: Print a struct by reference.
void print_struct(const struct S& s)
{
std::cout << s.c << ',' << s.i << '\n';
}
// f: a non-overloaded version of the preceding function.
void f(const struct S& s)
{
std::cout << s.c << ',' << s.i << '\n';
}
I compiled this in openSUSE 12.2 using:
g++-4.7 -ansi -Wall for_each.cpp -o for_each
The full error message is:
for_each.cpp: In function ‘int main()’:
for_each.cpp:31:48: error: no matching function for call to ‘for_each(std::vector<S>::iterator, std::vector<S>::iterator, <unresolved overloaded function type>)’
for_each.cpp:31:48: note: candidate is:
In file included from /usr/include/c++/4.7/algorithm:63:0,
from for_each.cpp:5:
/usr/include/c++/4.7/bits/stl_algo.h:4436:5: note: template<class _IIter, class _Funct> _Funct std::for_each(_IIter, _IIter, _Funct)
/usr/include/c++/4.7/bits/stl_algo.h:4436:5: note: template argument deduction/substitution failed:
for_each.cpp:31:48: note: couldn't deduce template parameter ‘_Funct’
I don't see any search results for this particular error on Stack Overflow, or on the web generally. Any help would be appreciated.
A names refers to an overload set. You'll need to specify which overload you want:
std::for_each(v.begin(), v.end(), (void (&)(S const&)) print_struct);
Another approach is to use a polymorphic callable function object as a helper:
struct PrintStruct
{
template <typename T> void operator()(T const& v) const
{ return print_struct(v); }
};
int main()
{
PrintStruct helper;
std::vector<S> sv;
std::vector<int> iv;
// helper works for both:
std::for_each(sv.begin(), sv.end(), helper);
std::for_each(iv.begin(), iv.end(), helper);
std::for_each declaration looks like this:
template<class InputIter, class Func>
void for_each(InputIter first, InputIter last, Func func);
As you can see, it takes anything you give it as the third parameter. There is no restriction that it has to be a callable type of a certain signature or a callable type at all.
When dealing with overloaded functions, they're inherently ambiguous unless you give them some context to select the right one. In a call to an overloaded function, this context are the arguments you pass. When you need a pointer, however, you can't use arguments as a context, and the for_each parameter also doesn't count as a context, since it takes anything.
As an example of where a function parameter can be a valid context to select the right overload, see this:
// our overloads
void f(int){}
void f(double){}
typedef void (*funcptr_type)(int);
void g(funcptr_type){}
// ...
g(&f); // will select 'void f(int)' overload, since that's
// the only valid one given 'g's parameter
As you can see, you give a clear context here that helps the compiler select the right overload and not have it ambiguous. std::for_each's parameters do not give such a context, since they take anything.
There are two solutions:
manually provide the context either by
casting to the right function pointer type, or
using an intermediate variable of the right type and passing that
use a non-overloaded function that dispatches to an overloaded one (as you did with f)
Note that in C++11, you could also use a lambda for the second option:
std::for_each(v.begin(), v.end(), [](const S& s){ print_struct(s); });
Some notes on your code:
(struct S){'a', 1} is a compound literal and not standard C++
you don't need struct S in C++, only S suffices