So I've added the use of lambdas in a C++ project and now the compiler is giving output like this:
9>C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxcallobj(13): warning C4800: 'BOOL' : forcing value to bool 'true' or 'false' (performance warning)
3> C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxfunction(386) : see reference to class template instantiation 'std::tr1::_Impl_no_alloc0<_Callable,_Rx>' being compiled
3> with
3> [
3> _Callable=_MyWrapper,
3> _Rx=bool
3> ]
3> C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxfunction(369) : see reference to function template instantiation 'void std::tr1::_Function_impl0<_Ret>::_Reset0o<_Myimpl,_Fty,std::allocator<_Ty>>(_Fty,_Alloc)' being compiled
3> with
3> [
3> _Ret=bool,
3> _Fty=`anonymous-namespace'::<lambda3>,
3> _Ty=std::tr1::_Function_impl0<bool>,
3> _Alloc=std::allocator<std::tr1::_Function_impl0<bool>>
3> ]
3> C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\functional(113) : see reference to function template instantiation 'void std::tr1::_Function_impl0<_Ret>::_Reset<_Fx>(_Fty)' being compiled
3> with
3> [
3> _Ret=bool,
3> _Fx=`anonymous-namespace'::<lambda3>,
3> _Fty=`anonymous-namespace'::<lambda3>
3> ]
3> ..\..\Common\IOFile.cpp(1162) : see reference to function template instantiation 'std::tr1::function<_Fty>::function<`anonymous-namespace'::<lambda3>>(_Fx)' being compiled
3> with
3> [
3> _Fty=bool (void),
3> _Fx=`anonymous-namespace'::<lambda3>
3> ]
And the code for my lambda is:
In the .h:
typedef std::function<bool ()> RepeatingFunction;
static bool RepeatFileOperation(RepeatingFunction callback);
static bool Copy(CString file, CString copyFileName, bool failIfExists = true);
In the .cpp:
bool IOFile::RepeatFileOperation(RepeatingFunction callback)
{
const int times_to_retry = 10;
bool succeed = false;
// Retry a few times if it doesn't work
int retries = 0;
do
{
// Perform the caller's action on the file
succeed = callback();
}
while (!succeed && retries++ < times_to_retry);
return succeed;
}
bool IOFile::Copy(CString file, CString copyFileName, bool failIfExists)
{
return RepeatFileOperation([&] {
return CopyFile(file, copyFileName, static_cast<BOOL>(failIfExists));
});
}
The program still compiles just fine. I Googled the error and can find people getting similar messages but in their case the program doesn't build. In all cases it appears that their build errors are about forward declaration, but as I said mine builds fine and I'm including <functional> in the header file so it should be able to find it fine.
Are these messages something I should be worried about or are they just expected behaviour?
CopyFile doesn't return a bool, but you are implicitly casting its result to a bool. Just add an explicit cast return static_cast<bool>(CopyFile(...
Related
Given this helper function:
template<typename Type>
std::string toString(Type const& value, bool encloseInQuotes = false) {
if constexpr (std::is_same<bool, Type>::value) {
auto s = value ? "true" : "false";
return encloseInQuotes ? "\""s + s + "\"" : s;
}
if constexpr (std::is_arithmetic<Type>::value) {
if (std::isnan(value)) {
return encloseInQuotes ? "\"NaN\"" : "NaN";
}
}
return "";
}
which is supposed to convert basic types (and strings) to a string expression, I get a compilation error with MSVC when using it like this:
int main() {
std::string temp = toString(true);
return 0;
}
With clang this compiles without any problem, with MSVC however I get this:
2>c:\program files (x86)\windows kits\10\include\10.0.10240.0\ucrt\math.h(403): error C2668: 'fpclassify': ambiguous call to overloaded function
2>c:\program files (x86)\windows kits\10\include\10.0.10240.0\ucrt\math.h(288): note: could be 'int fpclassify(long double) noexcept'
2>c:\program files (x86)\windows kits\10\include\10.0.10240.0\ucrt\math.h(283): note: or 'int fpclassify(double) noexcept'
2>c:\program files (x86)\windows kits\10\include\10.0.10240.0\ucrt\math.h(278): note: or 'int fpclassify(float) noexcept'
2>c:\program files (x86)\windows kits\10\include\10.0.10240.0\ucrt\math.h(403): note: while trying to match the argument list '(_Ty)'
2> with
2> [
2> _Ty=int
2> ]
2>: note: see reference to function template instantiation 'bool isnan(_Ty) noexcept' being compiled
2> with
2> [
2> Type=int,
2> _Ty=int
2> ]
Obviously the compiler considers the if constexpr (std::is_arithmetic<Type>::value) test as valid alternative too and generates the mentioned error. However, at runtime it correctly takes the path for bool (when I leave out the if constexpr (std::is_arithmetic<Type>::value) part or use a cast if (std::isnan(static_cast<double>(value)))).
How can I make this compile correctly on Windows as well?
For bool at least two type traits return true:
std::is_same<bool, Type>::value
std::is_arithmetic<Type>::value
and then you make a call std::isnan(true). Use else if:
if constexpr (std::is_same<bool, Type>::value) {
auto s = value ? "true" : "false";
return encloseInQuotes ? "\""s + s + "\"" : s;
}
else if constexpr (std::is_arithmetic<Type>::value) {
if (std::isnan(value)) {
return encloseInQuotes ? "\"NaN\"" : "NaN";
}
...
}
else
return "";
std::isnan and std::isinf seemingly internally calls fpclassify in MSVC. This function is overloaded for floating-point types, and you pass an argument of type bool, thus the call is ambiguous.
To avoid this, you may cast the arguments, e.g., to double:
if constexpr (std::is_arithmetic<Type>::value) {
if (std::isinf((double)value)) {
return encloseInQuotes ? "\"INF\"" : "INF";
}
if (std::isnan((double)value)) {
return encloseInQuotes ? "\"NaN\"" : "NaN";
}
Live demo: https://godbolt.org/z/W7Z3r3
UPDATE
This seems to be a bug in MSVC implementation, since, according to cppreference, there should be an overload for integral arguments that behaves the same as the double overload. Minimal example:
auto b = std::isnan(1);
Live demo: https://godbolt.org/z/qcTfQs
I have written (partailly copied :) ) the following code:
HigherOrderFunctions.h :
#ifndef HigherOrderFunctions_H
#define HigherOrderFunctions_H
#include <algorithm>
class HigherOrderFunctions {
public:
template<class Coll, class Func>
static Coll& filter(Coll& items, Func&& filterFunc);
private:
HigherOrderFunctions() {}
};
template < class Coll, class Func>
Coll& HigherOrderFunctions::filter(Coll& items, Func&& filterFunc) {
auto first = std::find_if_not(items.begin(), items.end(), filterFunc);
const auto last = items.end();
if (first != last) {
for(auto it = first; ++it != last; ) {
if (filterFunc(*it)) {
*first++ = std::move(*it);
}
}
}
items.erase(first, items.end());
return items;
}
#endif // HigherOrderFunctions_H
Now when I try to test the above code with the test function:
void HighOrderFunctionsTest::testFilter() {
vector<int> integers = {1, 2, 3, 4, 5, 6, 7};
HigherOrderFunctions::filter(integers, [](int elem) -> bool {
return (elem % 2) == 0;
});
const int ADULT_AGE = 18;
map<string, int> name_age_list = {{"sm", 10}, {"ak", 20}, {"al", 30}, {"am", 35}};
function<bool(const pair<string, int>&)> funct = [ADULT_AGE](const pair<string, int>& elem) -> bool {
return (elem.second > ADULT_AGE);
};
HigherOrderFunctions::filter(name_age_list, funct);
}
The part where I filter the vector compiles OK, but when I add the part with map I get the following compile error (using MSVS 2013):
HighOrderFunctionsTest.cpp
2>C:\winapp\MSVS2013PRO\VC\include\utility(175): error C2678: binary '=' : no operator found which takes a left-hand operand of type 'const std::string' (or there is no acceptable conversion)
2> C:\winapp\MSVS2013PRO\VC\include\xstring(1017): could be 'std::basic_string<char,std::char_traits<char>,std::allocator<char>> &std::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator =(_Elem)'
2> with
2> [
2> _Elem=char
2> ]
2> C:\winapp\MSVS2013PRO\VC\include\xstring(1012): or 'std::basic_string<char,std::char_traits<char>,std::allocator<char>> &std::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator =(const _Elem *)'
2> with
2> [
2> _Elem=char
2> ]
2> C:\winapp\MSVS2013PRO\VC\include\xstring(996): or 'std::basic_string<char,std::char_traits<char>,std::allocator<char>> &std::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator =(const std::basic_string<char,std::char_traits<char>,std::allocator<char>> &)'
2> C:\winapp\MSVS2013PRO\VC\include\xstring(957): or 'std::basic_string<char,std::char_traits<char>,std::allocator<char>> &std::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator =(std::initializer_list<_Elem>)'
2> with
2> [
2> _Elem=char
2> ]
2> C:\winapp\MSVS2013PRO\VC\include\xstring(901): or 'std::basic_string<char,std::char_traits<char>,std::allocator<char>> &std::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator =(std::basic_string<char,std::char_traits<char>,std::allocator<char>> &&) throw()'
2> while trying to match the argument list '(const std::string, const std::string)'
2> C:\winapp\MSVS2013PRO\VC\include\utility(174) : while compiling class template member function 'std::pair<const _Kty,_Ty> &std::pair<const _Kty,_Ty>::operator =(std::pair<const _Kty,_Ty> &&)'
2> with
2> [
2> _Kty=std::string
2> , _Ty=int
2> ]
2> D:\tax\tax_win\tc\src\cpp\foundation\HigherOrderFunctions.h(219) : see reference to function template instantiation 'std::pair<const _Kty,_Ty> &std::pair<const _Kty,_Ty>::operator =(std::pair<const _Kty,_Ty> &&)' being compiled
2> with
2> [
2> _Kty=std::string
2> , _Ty=int
2> ]
2> ..\..\..\..\..\..\src\cpp\foundation\test\HighOrderFunctionsTest.cpp(33) : see reference to class template instantiation 'std::pair<const _Kty,_Ty>' being compiled
2> with
2> [
2> _Kty=std::string
2> , _Ty=int
2> ]
I have looked for similar errors and I found out that this could happen if my function where the code is called would be const, but it is not. Can you please help me with this problem?
The problem is cause by *first++ = std::move(*it); line. When container is a map then stored items will be of type pair<const Key, Value>. De-referencing iterator will yield a reference to such a type and any attempt to perform move assignment to it will fail because the value of Key can not be changed.
I think the key issue with this code is that filter function is supposed to produce a new container with filtered values, not mutate supplied container. Currently implemented algorithm seems to be working similar to std::remove_if.
I've implemented a custom container class together with its iterator, and trying to use a for_each on it. Everything compiles fine in VC6, online cpp.sh and MSVC15, the latter only in release: when in debug I got a series of errors I report, under, the oversimplified version of my code.
struct Functor {
void operator()(int&) {}
} func;
struct Container {
typedef int value_type;
struct iterator {
bool operator!=(iterator const&) { return true; }
iterator& operator++() { return *this; }
value_type& operator*() { return i; } //this is just to compile, not for real
int i; //this is just to compile, not for real
};
iterator begin() { return iterator(); }
iterator end() { return iterator(); }
};
#include <algorithm>
int main() {
Container c;
std::for_each(c.begin(), c.end(), func); // compile errors
return 0;
}
Errors:
1>c:\program files\microsoft visual studio 14.0\vc\include\xutility(838): error C2672: '_Iter_cat': no matching overloaded function found
1> c:\program files\microsoft visual studio 14.0\vc\include\algorithm(31): note: see reference to function template instantiation 'void std::_Debug_range_ptr<_InIt,_Fn1>(_InIt,_InIt,_Pty &,std::_Dbfile_t,std::_Dbline_t)' being compiled
1> with
1> [
1> _InIt=Container::iterator,
1> _Fn1=Functor,
1> _Pty=Functor
1> ]
1> [...]: note: see reference to function template instantiation '_Fn1 std::for_each<Container::iterator,Functor>(_InIt,_InIt,_Fn1)' being compiled
1> with
1> [
1> _Fn1=Functor,
1> _InIt=Container::iterator
1> ]
1>c:\program files\microsoft visual studio 14.0\vc\include\xutility(838): error C2893: Failed to specialize function template 'iterator_traits<_Iter>::iterator_category std::_Iter_cat(const _Iter &)'
1> c:\program files\microsoft visual studio 14.0\vc\include\xutility(838): note: With the following template arguments:
1> c:\program files\microsoft visual studio 14.0\vc\include\xutility(838): note: '_Iter=Container::iterator'
1>c:\program files\microsoft visual studio 14.0\vc\include\xutility(838): error C2672: '_Debug_range_ptr2': no matching overloaded function found
1>c:\program files\microsoft visual studio 14.0\vc\include\xutility(838): error C2780: 'void std::_Debug_range_ptr2(_RanIt,_RanIt,_Pty &,std::_Dbfile_t,std::_Dbline_t,std::random_access_iterator_tag)': expects 6 arguments - 5 provided
1> c:\program files\microsoft visual studio 14.0\vc\include\xutility(820): note: see declaration of 'std::_Debug_range_ptr2'
1>c:\program files\microsoft visual studio 14.0\vc\include\xutility(838): error C2780: 'void std::_Debug_range_ptr2(_InIt,_InIt,_Pty &,std::_Dbfile_t,std::_Dbline_t,std::input_iterator_tag)': expects 6 arguments - 5 provided
1> c:\program files\microsoft visual studio 14.0\vc\include\xutility(811): note: see declaration of 'std::_Debug_range_ptr2'
MSVC has more extensive debug checks when using iterators. Presumably this requires a more complete definition of the iterator with all its embedded types.
Traditionally iterators have been derived from std::iterator<> that provides default definitions for the embedded types required.
template<
class Category,
class T,
class Distance = std::ptrdiff_t,
class Pointer = T*,
class Reference = T&
> struct iterator;
A change to the code as follows should clear things up;
struct iterator : std::iterator<
std::input_iterator_tag, // or as required
int
>
Usually iterators are defined as derived classes of the standard class std::iterator that is declared like
template<class Category, class T, class Distance = ptrdiff_t,
class Pointer = T*, class Reference = T&> struct iterator;
One of its template parameters is Category that determinates the category tag of the iterator such as for example std::input_iterator_tag.
In the debug mode the compiler performs some checks based on the category of the iterator.
You should follow this standard model of defining iterators.
The following code is failing to compile with
error C3497: you cannot construct an instance of a lambda`:
auto hasher = [&](const cv::Vec3b& color) -> size_t {
std::hash<int> int_hasher;
return int_hasher(color[0]) + int_hasher(color[1]) + int_hasher(color[2]);
// the above code is probably a wrong way of constructing a hash,
// but I'd like to get it to compile first
};
std::unordered_map<cv::Vec3b, int, decltype(hasher)> color_counts(10, hasher);
I noticed sometimes this happens when headers are not included. These are the included headers:
#include <unordered_map>
#include <functional>
#include "opencv2/core/core.hpp"
Note: I use the same technique for a comparator for priority queues in VS 2013, and it works. I see there's an alternative using std::function but I'd like to make this method work.
EDIT: Complete error log
error C3497: you cannot construct an instance of a lambda
2> E:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xhash(164) : while compiling class template member function 'OSLSegmentation::read_images::<lambda_52090ebe4a9b9afa82eb49e6ee9eb824> std::_Hash_oper1<false,_Hasher>::_Gethash(void) const'
2> with
2> [
2> _Hasher=OSLSegmentation::read_images::<lambda_52090ebe4a9b9afa82eb49e6ee9eb824>
2> ]
2> E:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xhash(242) : see reference to function template instantiation 'OSLSegmentation::read_images::<lambda_52090ebe4a9b9afa82eb49e6ee9eb824> std::_Hash_oper1<false,_Hasher>::_Gethash(void) const' being compiled
2> with
2> [
2> _Hasher=OSLSegmentation::read_images::<lambda_52090ebe4a9b9afa82eb49e6ee9eb824>
2> ]
2> E:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xhash(198) : see reference to class template instantiation 'std::_Hash_oper1<false,_Hasher>' being compiled
2> with
2> [
2> _Hasher=OSLSegmentation::read_images::<lambda_52090ebe4a9b9afa82eb49e6ee9eb824>
2> ]
2> E:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xhash(220) : see reference to class template instantiation 'std::_Hash_oper2<false,_Hasher,_Keyeq>' being compiled
2> with
2> [
2> _Hasher=OSLSegmentation::read_images::<lambda_52090ebe4a9b9afa82eb49e6ee9eb824>
2> , _Keyeq=std::equal_to<cv::Vec3b>
2> ]
2> E:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\unordered_map(23) : see reference to class template instantiation 'std::_Uhash_compare<_Kty,_Hasher,_Keyeq>' being compiled
2> with
2> [
2> _Kty=cv::Vec3b
2> , _Hasher=OSLSegmentation::read_images::<lambda_52090ebe4a9b9afa82eb49e6ee9eb824>
2> , _Keyeq=std::equal_to<cv::Vec3b>
2> ]
2> E:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xhash(255) : see reference to class template instantiation 'std::_Umap_traits<_Kty,_Ty,std::_Uhash_compare<_Kty,_Hasher,_Keyeq>,_Alloc,false>' being compiled
2> with
2> [
2> _Kty=cv::Vec3b
2> , _Ty=int
2> , _Hasher=OSLSegmentation::read_images::<lambda_52090ebe4a9b9afa82eb49e6ee9eb824>
2> , _Keyeq=std::equal_to<cv::Vec3b>
2> , _Alloc=std::allocator<std::pair<const cv::Vec3b,int>>
2> ]
2> E:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\unordered_map(81) : see reference to class template instantiation 'std::_Hash<std::_Umap_traits<_Kty,_Ty,std::_Uhash_compare<_Kty,_Hasher,_Keyeq>,_Alloc,false>>' being compiled
2> with
2> [
2> _Kty=cv::Vec3b
2> , _Ty=int
2> , _Hasher=OSLSegmentation::read_images::<lambda_52090ebe4a9b9afa82eb49e6ee9eb824>
2> , _Keyeq=std::equal_to<cv::Vec3b>
2> , _Alloc=std::allocator<std::pair<const cv::Vec3b,int>>
2> ]
2> oslsegmentation.cpp(42) : see reference to class template instantiation 'std::unordered_map<cv::Vec3b,int,OSLSegmentation::read_images::<lambda_52090ebe4a9b9afa82eb49e6ee9eb824>,std::equal_to<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>' being compiled
2> with
2> [
2> _Kty=cv::Vec3b
2> , _Ty=int
2> ]
What am I doing wrong here?
Figured it out after Kerrek's comment:
change this:
auto hasher = [&](const cv::Vec3b& color) -> size_t {
std::hash<int> int_hasher;
return int_hasher(color[0]) + int_hasher(color[1]) + int_hasher(color[2]);
// the above code is probably a wrong way of constructing a hash,
// but I'd like to get it to compile first
};
to (note the reference):
auto& hasher = [&](const cv::Vec3b& color) -> size_t {
std::hash<int> int_hasher;
return int_hasher(color[0]) + int_hasher(color[1]) + int_hasher(color[2]);
// the above code is probably a wrong way of constructing a hash,
// but I'd like to get it to compile first
};
Is the following code supposed to produce compilation error according to C++11 (if so why?) or is it a problem with VC11?
#include <vector>
#include <list>
#include <memory>
struct A
{
std::vector<std::unique_ptr<int>> v;
};
int main()
{
std::list<A> l;
l.sort([](const A& a1, const A& a2){ return true; });
}
Visual C++ 2012 produces the following compilation error:
1>c:\program files (x86)\microsoft visual studio 11.0\vc\include\xmemory0(606): error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>'
1> with
1> [
1> _Ty=int
1> ]
1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\memory(1447) : see declaration of 'std::unique_ptr<_Ty>::unique_ptr'
1> with
1> [
1> _Ty=int
1> ]
1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\xmemory0(605) : while compiling class template member function 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)'
1> with
1> [
1> _Ty=std::unique_ptr<int>
1> ]
1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\xmemory0(751) : see reference to function template instantiation 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)' being compiled
1> with
1> [
1> _Ty=std::unique_ptr<int>
1> ]
1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\type_traits(743) : see reference to class template instantiation 'std::allocator<_Ty>' being compiled
1> with
1> [
1> _Ty=std::unique_ptr<int>
1> ]
1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\vector(655) : see reference to class template instantiation 'std::is_empty<_Ty>' being compiled
1> with
1> [
1> _Ty=std::allocator<std::unique_ptr<int>>
1> ]
1> d:\test2\test2.cpp(213) : see reference to class template instantiation 'std::vector<_Ty>' being compiled
1> with
1> [
1> _Ty=std::unique_ptr<int>
1> ]
It's "a problem with VC", but only because you're misusing Visual Studio.
VC++ implements r-value references, but it does not implement compiler-generated move constructors/assignment operators. Which means that, if you want a type to be moveable, you must write one yourself.
A is not a moveable type, so the various std::list functions will attempt to copy them. And they'll fail when they try to copy a vector of unique_ptr. Hence the compiler error.
If you want move-aware objects in VC++, you must write move constructors/assignments for them yourself.
The problem is really in VC11, as it doesn't implement C++11 feature of automatically generating move operations (as already nailed by Nicol Bolas).
The following code compiles with VC10 SP1; in this code sample, move constructor is explicitly written (instead for move operator=, the copy-and-swap idiom is used).
#include <algorithm> // for std::swap (for copy-and-swap idiom)
#include <list>
#include <memory>
#include <vector>
struct A
{
std::vector<std::unique_ptr<int>> v;
A(A&& other)
: v( std::move(other.v) )
{
}
A& operator=(A other)
{
swap(*this, other);
return *this;
}
friend void swap(A& lhs, A& rhs)
{
using std::swap;
swap(lhs.v, rhs.v);
}
};
int main()
{
std::list<A> l;
l.sort( []( const A& , const A& ){ return true; } );
}
It was an issue with Visual C++ 2012 (acknowledged by Microsoft on Connect: Compile error in C++ code sorting a list of objects holding a vector of unique_ptr) and it was already fixed in Visual C++ 2013.
Also, I'd like to point out that an issue had nothing to do with the fact, that Visual C++ does not implicitly generate move constructors. If you explicitly delete all copy and move constructors in struct A (yes, it will make impossible inserting objects of type A into the list, but that is beside the point) in my original example the code still is not supposed to copy or move any objects and as such produce compilation errors:
#include <vector>
#include <list>
#include <memory>
struct A
{
std::vector<std::unique_ptr<int>> v;
A(A&&) = delete;
A(const A&) = delete;
};
int main()
{
std::list<A> l;
l.sort([](const A& a1, const A& a2){ return true; });
}