I'm getting a warning for the following code, which dissapears if I remove boost::blank from the variant:
namespace DB
{
struct Value{};
struct Container{};
}
typedef boost::variant <boost::blank, DB::Value, DB::Container> CommandData;
struct Command {
explicit Command(CommandData& _data): data(_data){
}
CommandData data;
};
int main()
{
CommandData commandData;
Command command(commandData);
return 0;
}
What's this issue?
Here's the warning:
1>: warning C4345: behavior change: an object of POD type constructed with an initializer of the form () will be default-initialized
1> c:\boost_1_49_0\boost\variant\variant.hpp(1224) : while compiling class template member function 'boost::variant<T0_,T1,T2>::variant(void)'
1> with
1> [
1> T0_=boost::blank,
1> T1=DB::Value,
1> T2=DB::Container
1> ]
1> c:\code.h(38) : see reference to class template instantiation 'boost::variant<T0_,T1,T2>' being compiled
1> with
1> [
1> T0_=boost::blank,
1> T1=DB::Value,
1> T2=DB::Container
1> ]
That warning is rather dumb. It warns that MSVC now does the right thing as opposed to some ancient version. You can turn it off with a pragma.
It's not because of the variant. Try to put int as a struct member for example instead of variant, and you'll get the same warning. The thing is that variant initializes with the first value by default, and boost::blank is a spectial type to optimize the variant behavior. See the variant documentation in Boost
Related
Wanting to investigate the performance hit (if any) of std:function.
I have this struct:
struct InstructionDescription
{
std::string name;
word mask;
word code;
std::function<void(Cpu*, word)> func;
word flags;
};
and I set up a vector of them like this
std::vector<InstructionDescription> instructions_{
{
{"clr", DD_MASK, 0005000, &Cpu::Clr},
{"clrb", DD_MASK, 0105000, &Cpu::Clr},
{"com", DD_MASK, 0005100, &Cpu::Com},
.....
Works fine. Now if I change the struct to use a function pointer:
using InstrFunc = void(*)(Cpu*, word);
struct InstructionDescription
{
std::string name;
word mask;
word code;
InstrFunc func;
word flags;
};
which as far as I can see should be equivalent. And yet I get
1>C:\work\pdp\mysim\mysim\instructions.h(60,50): error C2664: 'std::vector<Cpu::InstructionDescription,std::allocator<Cpu::InstructionDescription>>::vector(std::initializer_list<_Ty>,const _Alloc &)': cannot convert argument 1 from 'initializer list' to 'std::initializer_list<_Ty>'
1> with
1> [
1> _Ty=Cpu::InstructionDescription,
1> _Alloc=std::allocator<Cpu::InstructionDescription>
1> ]
1> and
1> [
1> _Ty=Cpu::InstructionDescription
1> ]
1>C:\work\pdp\mysim\mysim\instructions.h(60,50): message : Element '1': no conversion from 'initializer list' to '_Ty'
1> with
1> [
1> _Ty=Cpu::InstructionDescription
1> ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.25.28610\include\vector(512,5): message : see declaration of 'std::vector<Cpu::InstructionDescription,std::allocator<Cpu::InstructionDescription>>::vector'
1>Console.cpp
VS2019. VS GUI is also highlighting the std::vector line saying 'InstructionDescription' is unknown and that the function names are not accessible (&Cpu::Clr for example)
The Cpu class is defined like:
struct Cpu {
void Clr(word) {};
void Com(word) {};
};
What am I doing wrong?
The std::function is very convenient: it recognizes that &Cpu::Clr is a member function whose first parameter will be a Cpu*.
When you make it a function pointer, this doesn't work like this. You have to use a member function pointer:
using InstrFunc = void (Cpu::*)(word);
Additional info
This is standard: std::function nicely copes with pointers to member functions by adding a pointer to the class as first argument. Of course, when you call it, you have to provide that additional parameter:
Cpu cpu;
for (auto& i:instructions_) {
i.func(&cpu, i.code); // as simple as that with std::function
}
When you go for the pointer to member function, it's less convenient:
Cpu cpu;
for (auto& i:instructions) {
(cpu.*i.func)(i.code);
}
Online demo (you need to comment/ comment out the specific lines)
My environment is Visual Stuido 2013, VC12, Boost 1.59.
The following code (a minimal repro of the real code):
#include "boost/thread.hpp"
#include "boost/optional.hpp"
class MyClass
{
public:
template <typename T>
operator const T& () const;
};
boost::optional<MyClass> foo()
{
boost::optional<MyClass> res;
return res;
}
int main(int argc)
{
foo();
}
Doesn't compile, the error:
1>------ Build started: Project: TestBoostOptional, Configuration: Debug x64 ------
1> main.cpp
1>c:\workspace\third_party\boost_1_59_0\boost/optional/optional.hpp(297): error C2664: 'void boost::optional_detail::optional_base::construct(MyClass &&)' : cannot convert argument 1 from 'boost::detail::thread_move_t' to 'const MyClass &'
1> with
1> [
1> T=MyClass
1> ]
1> Reason: cannot convert from 'boost::detail::thread_move_t' to 'const MyClass'
1> with
1> [
1> T=MyClass
1> ]
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1> c:\workspace\third_party\boost_1_59_0\boost/optional/optional.hpp(292) : while compiling class template member function 'boost::optional_detail::optional_base::optional_base(boost::optional_detail::optional_base &&)'
1> with
1> [
1> T=MyClass
1> ]
1> c:\workspace\third_party\boost_1_59_0\boost/optional/optional.hpp(873) : see reference to function template instantiation 'boost::optional_detail::optional_base::optional_base(boost::optional_detail::optional_base &&)' being compiled
1> with
1> [
1> T=MyClass
1> ]
1> c:\workspace\third_party\boost_1_59_0\boost/optional/optional.hpp(766) : see reference to class template instantiation 'boost::optional_detail::optional_base' being compiled
1> with
1> [
1> T=MyClass
1> ]
1> main.cpp(14) : see reference to class template instantiation 'boost::optional' being compiled
Note the #include "boost/thread.hpp". When removing this include the code compiles. Anything that can be done to workaround?
You must define BOOST_THREAD_USES_MOVE before you use any boost header.
#define BOOST_THREAD_USES_MOVE
More information are located here. This define emulates a move by Boost.Move which is necessary here.
In order to implement Movable classes, move parameters and return
types Boost.Thread uses the rvalue reference when the compiler support
it. On compilers not supporting it Boost.Thread uses either the
emulation provided by Boost.Move or the emulation provided by the
previous versions of Boost.Thread depending whether
BOOST_THREAD_USES_MOVE is defined or not. This macros is unset by
default when BOOST_THREAD_VERSION is 2. Since BOOST_THREAD_VERSION 3,
BOOST_THREAD_USES_MOVE is defined.
Also see Boost.Move:
Boost.Thread uses by default an internal move semantic implementation.
Since version 3.0.0 you can use the move emulation emulation provided
by Boost.Move.
When BOOST_THREAD_VERSION==2 define BOOST_THREAD_USES_MOVE if you want
to use Boost.Move interface. When BOOST_THREAD_VERSION==3 define
BOOST_THREAD_DONT_USE_MOVE if you don't want to use Boost.Move
interface.
Here is a SSCCE:
#include <memory>
#include <vector>
template <class T> struct my_allocator : std::allocator<T> {
//This overriding struct causes the error
template <class U> struct rebind {
typedef my_allocator<T> other;
};
//Ignore all this.
typedef std::allocator<T> base;
typename base::pointer allocate(typename base::size_type n, std::allocator<void>::const_pointer /*hint*/=nullptr) { return (T*)malloc(sizeof(T)*n); }
void deallocate(typename base::pointer p, typename base::size_type /*n*/) { free(p); }
};
int main(int /*argc*/, char* /*argv*/[]) {
std::vector<int,my_allocator<int>> vec;
return 0;
}
GCC likes it.
ICC likes it.
Clang likes it.
Even MSVC 2013 likes it.
But MSVC 2015 RC spits out:
1>------ Build started: Project: Test Alloc, Configuration: Debug Win32 ------
1> main.cpp
1>c:\program files (x86)\microsoft visual studio 14.0\vc\include\vector(579): error C2664: 'void std::_Wrap_alloc<my_allocator<int>>::deallocate(int *,unsigned int)': cannot convert argument 1 from 'std::_Container_proxy *' to 'int *'
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\vector(579): note: Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\vector(574): note: while compiling class template member function 'void std::_Vector_alloc<std::_Vec_base_types<_Ty,_Alloc>>::_Free_proxy(void)'
1> with
1> [
1> _Ty=int,
1> _Alloc=my_allocator<int>
1> ]
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\vector(541): note: see reference to function template instantiation 'void std::_Vector_alloc<std::_Vec_base_types<_Ty,_Alloc>>::_Free_proxy(void)' being compiled
1> with
1> [
1> _Ty=int,
1> _Alloc=my_allocator<int>
1> ]
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\vector(668): note: see reference to class template instantiation 'std::_Vector_alloc<std::_Vec_base_types<_Ty,_Alloc>>' being compiled
1> with
1> [
1> _Ty=int,
1> _Alloc=my_allocator<int>
1> ]
1> c:\users\ian mallett\desktop\test-alloc\main.cpp(18): note: see reference to class template instantiation 'std::vector<int,my_allocator<int>>' being compiled
Related program give similarly fishy sounding errors. Here are two:
error C2664: 'void std::_Wrap_alloc>::deallocate(int *,unsigned int)': cannot convert argument 1 from 'std::_Container_proxy *' to 'int *'
cannot convert argument 1 from 'std::_Wrap_alloc>' to 'const aligned_allocator &'
Boolean question: is this a bug? Iff it is, I will (try) to submit it.
[EDIT: as noted in the comments, this only occurs in debug mode. In release mode, it compiles and executes fine.]
[EDIT: much simpler example]
Boolean question: is this a bug?
false.
Although the template error given by MSVC here is surpassingly unhelpful, the error here is mine (reassuring since this version of the standard library is shipping today).
I created this allocator (and later, the reduced test case) from a variety of sources, which is why I assumed it was correct. However, as suggested in the comments, I checked again, this time exhaustively against the documentation.
The missing component here is one of the copy constructors (the template one that can't be auto-generated). This only shows up when the rebind struct is defined since the rebind struct overrides the same struct in the parent class (which, since it's in the parent class, ultimately causes the parent's copy constructor to be called, so there's no problem (except that it's technically wrong)).
The interesting thing here is that the error didn't occur until now. As I said, GCC, Clang, and MSVC 2013 all like it (even with their respective debug modes). It's just that none of these happened to call the template copy constructor. Nevertheless, it is specified by the standard, so again, the error is ultimately mine.
Congratulations to the MSVC compiler team, and sorry for the noise! :D
Edit:
This has been reported as a VS2012 C++ compiler bug on Microsoft Connect (link).
Nov. 11, 2014: Microsoft has responded saying the fix for this bug should show up in the next major release of Visual C++.
I've been struggling with a VS2012 compiler error message I don't understand, so I trimmed down the problem to what seems like the bare minimum.
I'm building the following main.cpp using VS2012:
#include <utility>
template <typename T>
struct A
{
T x;
A(A&& other) : x(std::move(other.x)) { }
A(T&& x) : x(std::move(x)) { }
};
template <typename T>
A<T> build(T&& x)
{
return A<T>(std::move(x));
}
int main(int argc, char* argv[])
{
auto f = []()
{
return build([](){}); //error here
};
return 0;
}
The salient point is that I'm trying to use a lambda as the template type T of the build function. The error message I get is:
1> main.cpp
1>C:\test\main.cpp(21): error C2664: 'A<T>::A(A<T> &&)' : cannot convert parameter 1 from 'A<T>' to 'A<T> &&'
1> with
1> [
1> T=void (__cdecl *)(void)
1> ]
1> and
1> [
1> T=main::<lambda_c3c618d445b3cb24eede9bf304860ad7>::()::<lambda_4240e93016e3e420ff8383c9350ae130>
1> ]
1> and
1> [
1> T=void (__cdecl *)(void)
1> ]
1> Reason: cannot convert from 'A<T>' to 'A<T>'
1> with
1> [
1> T=main::<lambda_c3c618d445b3cb24eede9bf304860ad7>::()::<lambda_4240e93016e3e420ff8383c9350ae130>
1> ]
1> and
1> [
1> T=void (__cdecl *)(void)
1> ]
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
I've done my research and looked up the page for the error message (link), but I still can't figure out what the problem is. Could you please explain this compiler error?
edit
Something is definitely weird here. If I change the code in main to look like this:
auto f = []()
{
int* n = new int(0);
auto g = [=](){ return *n; };
*n++;
return build<decltype(g)>(std::move(g));
};
I get an error message suggesting that T=int (__cdecl *)(void) in the call to build - which would mean that decltype(g) is giving me a function pointer? Huh? I'm capturing a pointer by value and then modifying it afterwards - shouldn't it have to create a functor - and one that has no cast to function pointer? Maybe I'm not understanding something.
See related: Lambda expressions : n3290 draft
Also, if this is a bug in the VS2012 compiler, can you think of a workaround?
I can confirm that using GCC (on linux), this code compiles just fine.
So I'd say that VisualStudio seems to be the source of the error.
I don't have Windows or Visual Studio to verify, nor do I have much experience with lambda functions in C++, but perhaps you need to include the (albeit empty) parameter list in the function? i.e. change line 21 to
return build([](){});
Both versions compile with GCC, but perhaps Visual Studio is a bit more picky.
The other question I might have is whether the lambda function you're defining at line 24 will work out since its return value involves the lambda function you're defining inside the function itself.
I do not know if that behavior comply with the standard but with VC++ 2019 that error happen only with the option /permissive-, then when the strict mode is on.
Nevertheless here is how to solve the problem, by just casting the lambda with a reference type:
template <typename FUNC>
void f(FUNC& o){}
int main()
{
f((std::function<void()>&)[](){});
// or also:
auto func = [](){};
f(func);
}
This code supposedly works with GCC - I am trying to get it to work with Visual Studio. I can't figure out if the code is actually faulty or I'm not doing something right with the port.
1>c:\somepath\aaa.h(52): error C2101: '&' on constant
1> c:\somepath\aaa.h(52): while compiling class template member function 'const blahblah::Message something::AClass<Type>::aMethod(void) const'
1> with
1> [
1> Type=const lala::BClass&
1> ]
1> c:\somepath\bbb.h(79) : see reference to class template instantiation 'something:AClass<Type>' being compiled
1> with
1> [
1> Type=const lala::BClass&
1> ]
1> MyApplication.cpp
Files
aaa.h:52 virtual const Type aMethod() const { return Type(); }
bbb.h:79 AClass<const BClass&> blahblahblah_;
Constructing T() where T is a reference type is not valid, and makes no sense. Some versions of gcc incorrectly accept it.