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)
Related
I know I could do this better with std::vector, but the application I am messing with, has already a bunch of CArray parameters on a lot of related functions ... and I will not change them all at the moment!
I simply want to define an empty CArray<CClass*> — array of pointers to CClass, so the problem can not be on the CClass constructor — as the default value of a function parameter.
Approach 1
If I try to do it with assignment operator and default constructor:
void Function(CArray<CClass*> parameter = CArray<CClass*>());
I get the error:
1>C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\atlmfc\include\afxTempl.h(262): error C2248: 'CObject::CObject' : cannot access private member declared in class 'CObject'
1> C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\atlmfc\include\afx.h(535) : see declaration of 'CObject::CObject'
1> C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\atlmfc\include\afx.h(510) : see declaration of 'CObject'
1> This diagnostic occurred in the compiler generated function 'CArray<TYPE>::CArray(const CArray<TYPE> &)'
1> with
1> [
1> TYPE=CClass *
1> ]
Approach 2
I also tried with a copy constructor:
void Function(CArray<Class*> parameter(CArray<CClass*>()));
I got the errors:
>File.cpp(line X): error C2664: 'FunctionClass::Function' : cannot convert parameter 1 from 'CArray<TYPE>' to 'CArray<TYPE> (__cdecl *)(CArray<TYPE> (__cdecl *)(void))'
1> with
1> [
1> TYPE=CClass*
1> ]
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
line X: contains a call supplying the parameter to Function, as shown: pFunctionClass->Function(parameter);
1>CFunctionClass.cpp(line Y): error C2511: 'void CFunctionClass::Function(CArray)' : overloaded member function not found in 'CShoePlaceDoc'
1> with
1> [
1> TYPE=CClass*
1> ]
1> FunctionClass.h(line A) : see declaration of 'CFunctionClass'
line Y contains the Function implementation header, as shown: `void CFunctionClass::Function(CArray parameter)
1>File.cpp(line Z): error C2660: 'CClassFunction::Function' : function does not take 0 arguments
line Z: contains a call to Functionwithout supplying it parameters, as shown: pClassFunction->Function();
The approach didn't work, but it got its way towards a conclusion: It is not possible to use a copy-constructor for assigning a default value for a function parameter.
Approach 3
And if I try with a lambda:
void Function(CArray<CClass*> parameter = [] () -> CArray<CClass*>{ return CArray<CClass*> (); } );
, then I will get multiple outputs of these two errors:
1>FunctionClass.h(line A): error C2440: 'default argument' : cannot convert from '`anonymous-namespace'::<lambda2>' to 'CArray<TYPE>'
1> with
1> [
1> TYPE=CClass*
1> ]
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>FunctionClass.h(line B): fatal error C1903: unable to recover from previous error(s); stopping compilation
line A: method declaration
line B: closing } of FunctionClass class that contains Function method
Origin of the problem
The root cause of the problem seems to be the fact that CArray is a class directly derived from CObject, which declares the assignment operator as private:
class AFX_NOVTABLE CObject
{
//...
private:
CObject(const CObject& objectSrc); // no implementation
void operator=(const CObject& objectSrc); // no implementation
//...
}
So, how can I supply an empty array as default value for the parameter?
With this declaration
void Function(CArray<CClass*> parameter /*...*/);
You can't. Calling this function will invoke the private copy constructor of CObject as you have noticed.
What you could do, is to add a object of static CArray<CClass*> in your class and initialize the function with a reference to it. This way it will be empty (as long as you do not populate it...) and you can perform a .IsEmpty() check on it.
private:
static CArray<CClass*> myObj;
//...
void Function(CArray<CClass*> ¶meter = myObj);
Or initialize it to 0. This way you simply check it by if (parameter) or if (NULL == parameter).
void Function(CArray<CClass*> *parameter = NULL);
I am using Visual Studio 2013.
I am using the following as part of my code:
#include <queue>
#include <curses> // pdcurses for mvprintw function
using namespace std;
typedef unsigned short ushort;
struct xy{
int x;
int y;
};
void move(ushort length, queue<xy>& test);
int main() {
// ...
}
void move(ushort length, queue<xy>& test) {
queue<xy> coord;
if (length <= test.size()) {
coord = test.pop();
mvprintw(coord.y, coord.x, " ");
}
// ...
}
If I were to use the queue I made (which does not allow for templates), setting it up to use that struct as its type, it works fine. However, I want to make use of a templated queue so I can use queues of other types as well. But when I use the c++ standard queue in the way given above, I get the following error:
error C2679: binary '=' : no operator found which takes a right-hand operand of type 'void' (or there is no acceptable conversion)
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\queue(101): could be 'std::queue<xy,std::deque<_Ty,std::allocator<_Ty>>> &std::queue<_Ty,std::deque<_Ty,std::allocator<_Ty>>>::operator =(std::queue<_Ty,std::deque<_Ty,std::allocator<_Ty>>> &&)'
1> with
1> [
1> _Ty=xy
1> ]
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\queue(43): or 'std::queue<xy,std::deque<_Ty,std::allocator<_Ty>>> &std::queue<_Ty,std::deque<_Ty,std::allocator<_Ty>>>::operator =(const std::queue<_Ty,std::deque<_Ty,std::allocator<_Ty>>> &)'
1> with
1> [
1> _Ty=xy
1> ]
1> while trying to match the argument list '(std::queue<xy,std::deque<_Ty,std::allocator<_Ty>>>, void)'
1> with
1> [
1> _Ty=xy
1> ]
Am I missing something simple? I don't see why it seems to think the pop function returns a void type. Does the queue not use pop() for what I think it does? Or is the error in how I am using the Queue in my code?
It looks like you meant to declare coord to be of type xy, not queue<xy>.
Popping from std::queue indeed returns nothing; it simply removes the front element. If you want the front element, call front and then pop.
coord = test.front();
test.pop();
I'm have a problem with *passing a deleter functor into a std::smart_ptr*. This is the first time I've tried anything like this, so I may be overlooking something very simple..
Here's what my functor class looks like;
#pragma once;
#ifndef ASSETDELETERS_H
#define ASSETDELETERS_H
#include "RenderSystem.h"
struct SourceImageDeleter
{
RenderSystem & refGraphicsRenderer;
unsigned int * ptrTextureID;
explicit SourceImageDeleter( RenderSystem & tempRef, unsigned int * tempPtrID )
: refGraphicsRenderer( tempRef ) ,
ptrTextureID(tempPtrID) {};
SourceImageDeleter( const SourceImageDeleter & originalCopy )
: refGraphicsRenderer( originalCopy.refGraphicsRenderer ) ,
ptrTextureID( originalCopy.ptrTextureID ) {};
void operator() ()
{
refGraphicsRenderer.deregisterTexture( ptrTextureID );
}
};
#endif
The RenderSystem::deregisterTexture function only requires one argument (unsigned int *), because of that, it's being passed at the creation of the functor. I've looked into the use of std::bind, but I don't have much experience with that and wasn't able to have much success using it instead of making a functor.
And here's the only method that uses it so far..
std::shared_ptr<SourceImage> Engine::createSourceImage( std::string tempFilepath )
{
SourceImage * tempImagePtr = new SourceImage( tempFilepath );
registerTexture( &tempImagePtr->textureID, &tempImagePtr->image );
return std::shared_ptr<SourceImage>( tempImagePtr , SourceImageDeleter( this->graphicsRenderer, &tempImagePtr->textureID ) );
}
I'm not sure why it's not working! I've basically been trying to have my smart_ptr run a custom deletion function all week, and between trying to figure out how pointers-to-method passing works, how std::bind/std::mem_fun_ref works, and how functors work has been stumping me all week..
Anyway, here's the compile error that Visual Studio has been giving me, I hope someone can help me figure out what I've been screwing up;
error C2064: term does not evaluate to a function taking 1 arguments
1> class does not define an 'operator()' or a user defined conversion operator to a pointer-to-function or reference-to-function that takes appropriate number of arguments
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\memory(1438) : see reference to function template instantiation 'void std::tr1::shared_ptr<_Ty>::_Resetp<_Ux,_Dx>(_Ux *,_Dx)' being compiled
1> with
1> [
1> _Ty=SourceImage,
1> _Ux=SourceImage,
1> _Dx=SourceImageDeleter
1> ]
1> c:\projects\source\engine.cpp(151) : see reference to function template instantiation 'std::tr1::shared_ptr<_Ty>::shared_ptr<SourceImage,SourceImageDeleter>(_Ux *,_Dx)' being compiled
1> with
1> [
1> _Ty=SourceImage,
1> _Ux=SourceImage,
1> _Dx=SourceImageDeleter
1> ]
(By the way, engine.cpp(151) is the return line inside Engine::createSourceImage shown above.. If I remove the deleter argument, the program compiles and runs fine aside from the obvious resource leaks associated with improper image deletion..)
std::shared_ptr passes in the pointer being deleted to the deleter, which is exactly what your error message says: the class does not define an operator() with the correct number of arguments.
Your deleter isn't expecting any parameters, so it won't work; you'll need to change it to void operator()(SourceImage*)
So I can't seem to properly fill the requirements for this constructor.
DIVA_STATUS DIVA_getObjectDetailsList (
IN BOOL pFirstTime,
IN time_t *initialTime,
IN int pListType,
IN int pObjectsListType,
IN int pMaxListSize,
IN DIVA_STRING pObjectName,
IN DIVA_STRING pObjectCategory
IN DIVA_STRING pMediaName
DIVA_LEVEL_OF_DETAIL pLevelOfDetail,
IN vector<DIVA_STRING> listPosition,
OUT vector<DIVA_OBJECT_DETAILS_LIST> *&pObjectDetailsList
)
The problem seems to be the last line which outputs a vector of classes (???). I'm a little rusty with C++ so I cant recall why you would dereference a reference call (*&).
DIVA_OBJECT_DETAILS_LIST is a class shown below:
class DIVA_OBJECT_DETAILS_LIST {
public:
int listType;
DIVA_STRING siteID;
vector<DIVA_STRING> *listPosition;
vector<DIVA_OBJECT_INFO> *objectInfo;
vector<DIVA_OBJECT_TAPE_INFO> *objectTapeInfo;
};
Here is what I get when I try compiling using VC++ 2008 Express
1>Compiling...
1>initiator.cpp
1>.\initiator.cpp(148) : error C2100: illegal indirection
1>.\initiator.cpp(148) : error C2665: 'DIVA_getObjectDetailsList' : none of the 2 overloads could convert all the argument types
1> z:\Mediavault1\Automation\DIVA_API\DIVArchiveAPI\CppAPI Test\include\DIVAapi.h(2191): could be 'DIVA_STATUS DIVA_getObjectDetailsList(bool,time_t,int,int,int,DIVA_STRING,DIVA_STRING,DIVA_STRING,DIVA_LEVEL_OF_DETAIL,std::vector<_Ty>,DIVA_OBJECT_DETAILS_LIST *&)'
1> with
1> [
1> _Ty=DIVA_STRING
1> ]
1> while trying to match the argument list '(bool, time_t, int, int, int, DIVA_STRING, DIVA_STRING, DIVA_STRING, DIVA_LEVEL_OF_DETAIL, std::vector<_Ty>, DIVA_OBJECT_DETAILS_LIST *)'
1> with
1> [
1> _Ty=DIVA_STRING
1> ]
Here is how I'm calling the constructor:
cr = DIVA_getObjectDetailsList (
_firstTime,
(time_t)_initDate,
(int)DIVA_OBJECTS_LIST,
(int)DIVA_OBJECTS_CREATED_SINCE,
_size,
_name,
_category,
_group,
DIVA_INSTANCE,
*_listType.listPosition,
&*_listType
);
_listType is DIVA_OBJECT_DETAILS_LIST. How do I pass it pointer by reference?
The problem appears to be with the second to last argument. You are passing a std::vector<DIVA_STRING>* when you should just be passing a std::vector<DIVA_STRING> (not a pointer).
But to help your understanding about the last argument, vector<DIVA_OBJECT_DETAILS_LIST>*& is a "reference to pointer to vector<DIVA_OBJECT_DETAILS_LIST>" type. That is, you should pass a pointer and it is passed by reference.
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