I've heard a little bit about reference-to-reference problem and this resolution. I'm not very good with C++ Committee terminology, but I understand the "Moved to DR" annotation in the link means that this is the current interpretation that standard-conforming compilers should adhere to.
I have this sample code that I can't understand:
template <typename T>
struct C {
void f(T&) { }
void f(const T&) { }
};
int main() {
C<int> x; // OK
C<int&> y; // compile error: f cannot be overloaded
C<const int&> z; // compile error: f cannot be overloaded
}
I understand the error in C<const int&> case: using rules from DR #106 we get two methods with the same signature f(const int&). What I don't get is the C<int&> case: shouldn't it generate exactly the same code as C<int> (at least according to Stroustrup's resolution)?
DR only means "Defect Report", and to my knowledge, the described resolution hasn't made it (yet) to the standard. For this reason, I believe a strictly conforming C++03 implementation should not compile this code because of it is forming a reference to a reference.
[Edit] Just found a nice answer on this issue.
Interestingly, when I compile your code (Visual C++ 10 Express) I get errors, but also when I try this simpler case:
int main(int argc, char* argv[])
{
C<int> x; // OK
C<const int> x1; // error C2535: 'void C<T>::f(T &)' : member function
// already defined or declared
return 0;
}
Seems like the ref-to-ref collapsing defined in the DR you mentioned means that const ref becomes a simple non-const ref within the template. My problem with this is that I don't understand why the second f is not just ignored.
If I change C so that the second f is const-qualified, this now compiles:
template <typename T>
struct C {
void f(T&) { }
void f(const T& t) const {}
};
The implication seems to be that when C is instantiated with const anything (ref or not), the two C::f overloads are simply identical, and result in compile-time duplicate detection.
Perhaps somebody smarter than me can decipher the chain more definitively here.
EDIT: On reflection, it's not surprising here that T = const int& results in the f overloads being identically instantiated as
void f(const int&) {}
That's what the compiler is telling me:
#include "stdafx.h"
template <typename T>
struct C {
void f(T&) { }
void f(const T&) { }
};
int main() {
C<const int&> z; // compile error: f cannot be overloaded
return 0;
}
gives this error:
1>test.cpp(6): error C2535: 'void C<T>::f(T)' : member function already
defined or declared
1> with
1> [
1> T=const int &
1> ]
1> test.cpp(5) : see declaration of 'C<T>::f'
1> with
1> [
1> T=const int &
1> ]
1> test.cpp(10) : see reference to class template instantiation
'C<T>' being compiled
1> with
1> [
1> T=const int &
1> ]
I'm not even convinced this has anything to do with the DR.
Related
While creating a subclass of a template class I noticed I got an error on an overloaded function.
This compiler error was correct since one of the overloads was using a copy and the type was not copyable.
However, I was not using that function (correct overload or not). So I was surprised to get this error
After searching around a bit and reproducing in godbolt the culprit seemed to be __declspec(dllexport).
Reproduction in godbolt
Removing the declspec seems to result in the correct compilation.
Code in godbolt:
#include <memory>
#include <vector>
using namespace std;
template<class V>
struct Foo{
void update(const V& v);
void update(V&& v);
std::vector<V> values;
};
template<class V>
void Foo<V>::update(const V& v)
{
values[0] = v;
}
template<class V>
void Foo<V>::update(V&& v)
{
values[0] = std::move(v);
}
struct __declspec(dllexport) Bar : public Foo<std::unique_ptr<int>>
{
};
int main()
{
Bar f;
auto i = std::make_unique<int>(5);
//f.update(i);
//f.update(std::move(i));
}
My questions are mostly, how is declspec causing this behavior?
And, is there anything that can be done about this in the template class or derived class?
Error log:
(19): error C2280:
'std::unique_ptr>
&std::unique_ptr>::operator =(const
std::unique_ptr> &)': attempting to
reference a deleted function with [
_Ty=int ] C:/data/msvc/14.16.27023.1/include\memory(2338): note: see declaration of
'std::unique_ptr>::operator =' with
[
_Ty=int ] C:/data/msvc/14.16.27023.1/include\memory(2338): note: 'std::unique_ptr>
&std::unique_ptr>::operator =(const
std::unique_ptr> &)': function was
explicitly deleted with [
_Ty=int ] (18): note: while compiling class template member function 'void
Foo>>::update(const V &)'
with [
_Ty=int,
V=std::unique_ptr> ] (29): note: see reference to class template instantiation
'Foo>>' being compiled
with [
_Ty=int ]
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 make a for_each function for a generic object that uses an size function and an item index function. But I'm having some difficulty with the syntax.
This is what I have so far (starting at line 128):
class base1
{
protected:
std::vector<int> items;
public:
base1()
: items({1,2,3})
{
}
int GetCount() const
{
}
};
class base2 : public base1
{
public:
base2()
: base1()
{
}
int GetItem(int i) const
{
return items[i];
}
};
class derived : public base2
{
public:
derived()
: base2()
{
}
};
template <typename CONTAINER, typename CONTAINER_BASE1, typename CONTAINER_BASE2, typename SIZE, typename CONTAINED, typename FUNC>
void for_each(CONTAINER* container, SIZE (CONTAINER_BASE1::*GetSize)() const, CONTAINED (CONTAINER_BASE2::*GetItem)(SIZE) const, FUNC& body)
{
for (SIZE i = 0; i < container->*GetSize(); ++i)
{
body(container->*GetItem(i));
}
}
void fn()
{
derived x;
for_each(&x, &derived::GetCount, &derived::GetItem, [](int i){
++i;
});
}
Right now, I get an error from VC++ 2013 stating:
1>d:\projects\test\test.cpp(169): error C2064: term does not evaluate to a function taking 0 arguments
1> d:\projects\test\test.cpp(180) : see reference to function template instantiation 'void for_each<derived,base1,base2,int,int,fn::<lambda_862ea397905775f7e094cde6fe9b462c>>(CONTAINER *,SIZE (__thiscall base1::* )(void) const,CONTAINED (__thiscall base2::* )(SIZE) const,FUNC &)' being compiled
1> with
1> [
1> CONTAINER=derived
1> , SIZE=int
1> , CONTAINED=int
1> , FUNC=fn::<lambda_862ea397905775f7e094cde6fe9b462c>
1> ]
1>d:\projects\test\test.cpp(171): error C2064: term does not evaluate to a function taking 1 arguments
Any ideas as to what the problem is?
You have two bugs. You take the functor by non-const lvalue reference - FUNC& body - which doesn't bind to a temporary like a lambda; this was hidden by a terrible MSVC extension that allows such bindings. You should accept the function object by value (the way it is usually done by the standard library), by const lvalue reference (if copying is expensive and/or identity is important), or by forwarding reference (if identity is important and operator() can be non-const).
Second is operator precedence. The postfix function call operator has higher precedence than .* and ->*. container->*GetSize() is container->*(GetSize()); you want (container->*GetSize)().
I'm also not sure about this design. It's probably better to provide a uniform interface, and simply do, e.g., container.size() and container.at(i) than using this tortured system of pointer-to-member-functions.
I recently spent quite some time understanding the error message when calling func() in this piece of code:
int main()
{
vector< vector<double> > v;
double sum = 0;
for_each( v.begin(), v.end(),
bind2nd( ptr_fun(func), &sum ) );
return 0;
}
when func() was declared like so, the code compiled fine:
void func( vector<double> v, double *sum )
{
}
when I used this declaration (for efficiency), I got a compiler error:
void func( const vector<double> &v, double *sum )
{
}
The error I expected to see was something like a reference-to-reference error, because of the definition of operator() of binder2nd,
result_type operator()(const argument_type& _Left) const
Instead, to my surprise, the error the Visual C++ (VS2012) compiler gave me was:
error C2535: 'void std::binder2nd<_Fn2>::operator ()(const
std::vector<_Ty> &) const' : member function already defined or
declared
which I cannot decipher.
Can you explain under which mechanism the operator() is already
defined?
The full error I got was:
error C2535: 'void std::binder2nd<_Fn2>::operator ()(const std::vector<_Ty> &) const' : member function already defined or declared
with
[
_Fn2=std::pointer_to_binary_function<const std::vector<double> &,double *,void,void (__cdecl *)(const std::vector<double> &,double *)>,
_Ty=double
]
c:\vc\include\xfunctional(319) : see declaration of 'std::binder2nd<_Fn2>::operator ()'
with
[
_Fn2=std::pointer_to_binary_function<const std::vector<double> &,double *,void,void (__cdecl *)(const std::vector<double> &,double *)>
]
c:\consoleapplication1.cpp(31) : see reference to class template instantiation 'std::binder2nd<_Fn2>' being compiled
with
[
_Fn2=std::pointer_to_binary_function<const std::vector<double> &,double *,void,void (__cdecl *)(const std::vector<double> &,double *)>
]
Build FAILED.
This behavior is well-defined (every correct C++ compiler will fail to compile your code).
From the standard (N3376) section D.9.3 on class template binder2nd, these two defintions of operator() exist:
typename Fn::result_type
operator()(const typename Fn::first_argument_type& x) const;
typename Fn::result_type
operator()(typename Fn::first_argument_type& x) const;
If first_argument_type is already a const T&, then they will be conflicting.
This isn't an answer, but I just want to record the modern C++11 solution, where all the small bind helpers are deprecated in favour of the universal std::bind:
#include <functional>
#include <vector>
#include <algorithm>
void func(std::vector<double> const & v, double * sum) { /* ... */ }
int main()
{
std::vector<std::vector<double>> v;
double sum = 0;
std::for_each(v.begin(), v.end(), std::bind(func, std::placeholders::_1, &sum));
}
The variadic templates of C++11, as well as a more comprehensive collection of type-modifying traits, give std::bind much stronger deduction abilities than the previous components in <functional>.
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.