When compiling the following code, Visual Studio reports:
\main.cpp(21): error C2664: 'std::_Call_wrapper<std::_Callable_pmd<int ClassA::* const ,_Arg0,false>,false> std::mem_fn<void,ClassA>(int ClassA::* const )' : cannot convert argument 1 from 'overloaded-function' to 'int ClassA::* const '
1> with
1> [
1> _Arg0=ClassA
1> ]
1> Context does not allow for disambiguation of overloaded function
Why is the compiler confused when creating mem_fptr1? But some how mem_fptr2 is ok when I specify the types.
Can I create member function pointer to an overloaded member function that takes no argument?
class ClassA
{
public:
void memberfunction()
{
std::cout <<"Invoking ClassA::memberfunction without argument" << std::endl;
}
void memberfunction(int arg)
{
std::cout << "Invoking ClassA::memberfunction with integer " << arg << std::endl;
}
};
int main()
{
auto mem_fptr1 = std::mem_fn<void, ClassA>(&ClassA::memberfunction);
auto mem_fptr2 = std::mem_fn<void, ClassA, int>(&ClassA::memberfunction);
mem_fptr1(ClassA());
mem_fptr2(ClassA(), 3);
}
The template overloads taking a variadic list of argument types were introduced in C++11 but removed in C++14 as defect #2048. The way to specify a particular overload is to specify a function type as the first template argument (the second template argument, the class type, can be omitted as it can be deduced):
auto mem_fptr1 = std::mem_fn<void()>(&ClassA::memberfunction);
auto mem_fptr2 = std::mem_fn<void(int)>(&ClassA::memberfunction);
The function type R is then composed with the class type T as R T::* to give the member function type. This also allows forming a std::mem_fn to a data member (where R is a non-function type).
Note that your code (for mem_fptr2) does not work in C++14 where the template overloads taking a variadic list of argument types are removed; the above code will work in both versions of the Standard.
An alternative is to perform a member function cast; in this case you do not need to specify template arguments to mem_fn:
auto mem_fptr1 = std::mem_fn(
static_cast<void (ClassA::*)()>(&ClassA::memberfunction));
auto mem_fptr2 = std::mem_fn(
static_cast<void (ClassA::*)(int)>(&ClassA::memberfunction));
Related
Windows 10, Visual Studio 2019, C++17:
Compile error:
cannot convert argument 2 from 'int (__cdecl *)(int)' to '...'
////////////////////////////////////////////////////////////////////
// This is the templated function that becomes a variadic argument
//
template <typename siz>
int func(siz size)
{
// ...
// ...
return 0;
}
///////////////////////////////////////////////////////////
// This is the function that uses variadic arguments
//
int usefunc(int option, ...)
{
// ...
// ...
return 0;
}
int main()
{
int result;
result = usefunc(0, func); // ** int usefunc(int,...)': cannot convert argument 2 from 'int (__cdecl *)(int)' to '...' **
// Context does not allow for disambiguation of overloaded function
return result;
}
Without the template (int func(int size) ) the code compiles ok. How do I modify this to make the compiler understand the variadic argument?
The issue is func is being treated as a function pointer, but pointers to template functions are not allowed in C++.
You need to specify the type you plan to use when you reference func, like:
result = usefunc(0, func<int>);
You can use decltype to reference the type of a variable, to be a little more flexible:
result = usefunc(0, func<decltype(result)>);
Given the following code :-
#include <algorithm>
#include <iostream>
#include <functional>
#include <string>
void func(std::function<void(void)> param)
{
param();
}
void func(std::function<void(int)> param)
{
param(5);
}
int main(int argc, char* argv[])
{
func([] () { std::cout << "void(void)" << std::endl; });
func([] (int i) { std::cout << "void(int): " << i << std::endl; });
std::string line;
std::getline(std::cin, line);
return 0;
}
Compile error from VS2010 :-
CppTest.cpp(18): error C2668: 'func' : ambiguous call to overloaded function
1> CppTest.cpp(11): could be 'void func(std::tr1::function<_Fty>)'
1> with
1> [
1> _Fty=void (int)
1> ]
1> CppTest.cpp(6): or 'void func(std::tr1::function<_Fty>)'
1> with
1> [
1> _Fty=void (void)
1> ]
1> while trying to match the argument list '(`anonymous-namespace'::<lambda0>)'
1>CppTest.cpp(19): error C2668: 'func' : ambiguous call to overloaded function
1> CppTest.cpp(11): could be 'void func(std::tr1::function<_Fty>)'
1> with
1> [
1> _Fty=void (int)
1> ]
1> CppTest.cpp(6): or 'void func(std::tr1::function<_Fty>)'
1> with
1> [
1> _Fty=void (void)
1> ]
1> while trying to match the argument list '(`anonymous-namespace'::<lambda1>)'
Compile error from g++-4.5
program2.cpp: In function ‘int main(int, char**)’:
program2.cpp:18:68: error: call of overloaded ‘func(main(int, char**)::<lambda()>)’ is ambiguous
program2.cpp:6:10: note: candidates are: void func(std::function<void()>)
program2.cpp:11:10: note: void func(std::function<void(int)>)
program2.cpp:19:79: error: call of overloaded ‘func(main(int, char**)::<lambda(int)>)’ is ambiguous
program2.cpp:6:10: note: candidates are: void func(std::function<void()>)
program2.cpp:11:10: note: void func(std::function<void(int)>)
So it seems the compiler can't figure out that a lambda [] () -> void can only be assigned to a std::function<void(void)>, and a lambda [] (int) -> void can only be assigned to a std::function<void(int)>. Is this supposed to happen or just a deficiency in the compilers?
Is this supposed to happen or just a deficiency in the compilers?
This is supposed to happen. std::function has a constructor template that can take an argument of any type. The compiler can't know until after a constructor template is selected and instantiated that it's going to run into errors, and it has to be able to select an overload of your function before it can do that.
The most straightforward fix is to use a cast or to explicitly construct a std::function object of the correct type:
func(std::function<void()>([](){}));
func(std::function<void(int)>([](int){}));
If you have a compiler that supports the captureless-lambda-to-function-pointer conversion and your lambda doesn't capture anything, you can use raw function pointers:
void func(void (*param)()) { }
void func(void (*param)(int)) { }
(It looks like you are using Visual C++ 2010, which does not support this conversion. The conversion was not added to the specification until just before Visual Studio 2010 shipped, too late to add it in.)
To explain the problem in a bit more detail, consider the following:
template <typename T>
struct function {
template <typename U>
function(U f) { }
};
This is basically what the std::function constructor in question looks like: You can call it with any argument, even if the argument doesn't make sense and would cause an error somewhere else. For example, function<int()> f(42); would invoke this constructor template with U = int.
In your specific example, the compiler finds two candidate functions during overload resolution:
void func(std::function<void(void)>)
void func(std::function<void(int)>)
The argument type, some unutterable lambda type name that we will refer to as F, doesn't match either of these exactly, so the compiler starts looking at what conversions it can do to F to try and make it match one of these candidate functions. When looking for conversions, it finds the aforementioned constructor template.
All the compiler sees at this point is that it can call either function because
it can convert F to std::function<void(void)> using its converting constructor with U = F and
it can convert F to std::function<void(int)> using its converting constructor with U = F.
In your example it is obvious that only one of these will succeed without error, but in the general case that isn't true. The compiler can't do anything further. It has to report the ambiguity and fail. It can't pick one because both conversions are equally good and neither overload is better than the other.
I'm trying to overload a Sum function which accepts a [list or vector] start and end iterator as arguments. This compiler error is really confusing me. Relevant code is as follows:
template <typename T1, typename T2>
const double Sum(const typename T1::const_iterator& start_iter, const typename T2::const_iterator& end_iter)
{// overloaded function that calculates sum between two iterators
typename T1::const_iterator iterator_begin = start_iter;
typename T2::const_iterator iterator_end = end_iter;
double my_sum = 0;
for (iterator_begin; iterator_begin != iterator_end; iterator_begin++)
my_sum += *iterator_begin;
return my_sum;
}
int main()
{
list<double> test_list(10,5.1);
cout << Sum(test_list.begin(), test_list.end()); // compiler errors here
}
I get the following compiler errors:
iterators.cpp(72): error C2783: 'const double Sum(const
T1::const_iterator &,const T2::const_iterator &)' : could not deduce
template argument for 'T1'
iterators.cpp(72): error C2783: 'const double Sum(const
T1::const_iterator &,const T2::const_iterator &)' : could not deduce
template argument for 'T2'
iterators.cpp(72): error C2780: 'const double Sum(const
std::map &)' : expects 1 arguments - 2 provided
iterators.cpp(72): error C2780: 'const double Sum(const T &)' :
expects 1 arguments - 2 provided
How is the compiler not recognizing I'm trying to call the Sum function with two inputs? I'm calling the function incorrectly?
Thanks!
You dont need to tell it that iterators have to be members of some types T1 and T2, just template it on iterator type itself:
template <typename Iter>
const double Sum(Iter iterator_begin, Iter iterator_end)
{
double my_sum = 0;
for (; iterator_begin != iterator_end; ++iterator_end)
my_sum += *iterator_begin;
return my_sum;
}
int main()
{
std::list<double> test_list;
std::cout << Sum(test_list.begin(), test_list.end());
return 0;
}
also there is a standard std::accumulate that does this:
int main()
{
std::list<double> test_list;
std::cout << std::accumulate(test_list.begin(), test_list.end(), 0.0);
return 0;
}
First, I don't think you want to do this. Not all sequences have an
underlying container. (Think of istream_iterators, for example.) And
more importantly, you're distinctly allowing (and even encouraging)
begin and end iterators from different containers; there is no case
where you could legally use this function where T1 and T2 have
different types. The template should have a single parameter, which
should be an iterator; and by convention, the constraints on the
iterator should be expressed in the name of the parameter, e.g.
InputIterator (the case here), ForwardIterator, etc.
As to why your code doesn't compile:
In most cases, the types, templates, and non-type values that are used
to compose P participate in template argument deduction. That is, they
may be used to determine the value of a template argument, and the
value so determined must be consistent with the values determined
elsewhere. In certain contexts, however, the value does not
participate in type deduction, but instead uses the values of template
arguments that were either deduced elsewhere or explicitly specified.
If a template parameter is used only in non-deduced contexts and is
not explicitly specified, template argument deduction fails.
The non-deduced contexts are:
— The nested-name-specifier of a type that was specified using a
qualified-id.
[...]
(From §14.8.2.5/4,5.)
Call method like this..
Sum<list<double>,list<double> >(test_list.begin(), test_list.begin());
Having the following code:
template<typename T, typename OutStream = std::ostream> struct print {
OutStream &operator()(T const &toPrint, OutStream &outStream = std::cout) const {
outStream << toPrint;
return outStream;
}
};
This call is erroneous:
print<int>(2);
Error message:
1>main.cpp(38): error C2440: '<function-style-cast>' : cannot convert from 'int' to 'print<T>'
1> with
1> [
1> T=int
1> ]
1> No constructor could take the source type, or constructor overload resolution was ambiguous
This call is not erroneous:
print<int> intPrinter;
intPrinter(2);
Can I use a function object somehow without its instantiation?
I cannot use a template function here, because I need partial specialization capabilities.
I think that you want to say
print<int>()(2);
Here, the first parens create a temporary print<int> object by calling the (zero-argument) constructor, then the second parens actually invoke the function call operator on that object. The error you're getting now is caused by the fact that
print<int>(2);
Is interpreted as a typecast expression to convert 2 into a print<int>, which isn't what you want (and also isn't legal).
Hope this helps!
For those stateless wrapper classes, it might be better to use static member functions:
template<typename T, typename OutStream = std::ostream>
struct printer
{
static OutStream & print()(T const &toPrint, OutStream &outStream = std::cout)
{
outStream << toPrint;
return outStream;
}
};
Then you can invoke them with printer<Foo>::print(x);, and you can typically supply a type-deducing helper function template:
template <typename T> std::ostream & print(T const & x)
{
return printer<T, std::ostream>::print(x);
}
Now you can just say print(x);.
Given the following code :-
#include <algorithm>
#include <iostream>
#include <functional>
#include <string>
void func(std::function<void(void)> param)
{
param();
}
void func(std::function<void(int)> param)
{
param(5);
}
int main(int argc, char* argv[])
{
func([] () { std::cout << "void(void)" << std::endl; });
func([] (int i) { std::cout << "void(int): " << i << std::endl; });
std::string line;
std::getline(std::cin, line);
return 0;
}
Compile error from VS2010 :-
CppTest.cpp(18): error C2668: 'func' : ambiguous call to overloaded function
1> CppTest.cpp(11): could be 'void func(std::tr1::function<_Fty>)'
1> with
1> [
1> _Fty=void (int)
1> ]
1> CppTest.cpp(6): or 'void func(std::tr1::function<_Fty>)'
1> with
1> [
1> _Fty=void (void)
1> ]
1> while trying to match the argument list '(`anonymous-namespace'::<lambda0>)'
1>CppTest.cpp(19): error C2668: 'func' : ambiguous call to overloaded function
1> CppTest.cpp(11): could be 'void func(std::tr1::function<_Fty>)'
1> with
1> [
1> _Fty=void (int)
1> ]
1> CppTest.cpp(6): or 'void func(std::tr1::function<_Fty>)'
1> with
1> [
1> _Fty=void (void)
1> ]
1> while trying to match the argument list '(`anonymous-namespace'::<lambda1>)'
Compile error from g++-4.5
program2.cpp: In function ‘int main(int, char**)’:
program2.cpp:18:68: error: call of overloaded ‘func(main(int, char**)::<lambda()>)’ is ambiguous
program2.cpp:6:10: note: candidates are: void func(std::function<void()>)
program2.cpp:11:10: note: void func(std::function<void(int)>)
program2.cpp:19:79: error: call of overloaded ‘func(main(int, char**)::<lambda(int)>)’ is ambiguous
program2.cpp:6:10: note: candidates are: void func(std::function<void()>)
program2.cpp:11:10: note: void func(std::function<void(int)>)
So it seems the compiler can't figure out that a lambda [] () -> void can only be assigned to a std::function<void(void)>, and a lambda [] (int) -> void can only be assigned to a std::function<void(int)>. Is this supposed to happen or just a deficiency in the compilers?
Is this supposed to happen or just a deficiency in the compilers?
This is supposed to happen. std::function has a constructor template that can take an argument of any type. The compiler can't know until after a constructor template is selected and instantiated that it's going to run into errors, and it has to be able to select an overload of your function before it can do that.
The most straightforward fix is to use a cast or to explicitly construct a std::function object of the correct type:
func(std::function<void()>([](){}));
func(std::function<void(int)>([](int){}));
If you have a compiler that supports the captureless-lambda-to-function-pointer conversion and your lambda doesn't capture anything, you can use raw function pointers:
void func(void (*param)()) { }
void func(void (*param)(int)) { }
(It looks like you are using Visual C++ 2010, which does not support this conversion. The conversion was not added to the specification until just before Visual Studio 2010 shipped, too late to add it in.)
To explain the problem in a bit more detail, consider the following:
template <typename T>
struct function {
template <typename U>
function(U f) { }
};
This is basically what the std::function constructor in question looks like: You can call it with any argument, even if the argument doesn't make sense and would cause an error somewhere else. For example, function<int()> f(42); would invoke this constructor template with U = int.
In your specific example, the compiler finds two candidate functions during overload resolution:
void func(std::function<void(void)>)
void func(std::function<void(int)>)
The argument type, some unutterable lambda type name that we will refer to as F, doesn't match either of these exactly, so the compiler starts looking at what conversions it can do to F to try and make it match one of these candidate functions. When looking for conversions, it finds the aforementioned constructor template.
All the compiler sees at this point is that it can call either function because
it can convert F to std::function<void(void)> using its converting constructor with U = F and
it can convert F to std::function<void(int)> using its converting constructor with U = F.
In your example it is obvious that only one of these will succeed without error, but in the general case that isn't true. The compiler can't do anything further. It has to report the ambiguity and fail. It can't pick one because both conversions are equally good and neither overload is better than the other.