I want to pass the standardized C++ binary functions to a template function, but somehow I didn't get it to work.
The following is my attempt to do it:
template<template <typename> typename Pred,typename T, typename Iterator>
void iota_stepa(Iterator begin, Iterator end, T startofSequence_, T threadStep)
{
int currMaxThreads = startofSequence_;
bool first = true;
generate(begin, end, Pred<T>(currMaxThreads, threadStep) );
}
and testing it with:
vector<int> tempVect_(10, 0);
iota_stepa<std::plus>(begin(tempVect_),end(tempVect_),1,thread::hardware_concurrency());
gives me unfortunately the errors:
Severity Code Description Project File Line Suppression State
Error C2440 '<function-style-cast>': cannot convert from 'initializer list' to 'std::plus<int>'
Error C2672 'generate': no matching overloaded function found FractalCarpet
Error C2780 'void std::generate(_FwdIt,_FwdIt,_Fn0)': expects 3 arguments - 2 provided FractalCarpet
The console output looks like the following:
1> c:\users\mtunca\documents\esd\sps\fractalcarpet\main.cpp(55): note: see reference to function template instantiation 'void iota_stepa<std::plus,int,std::_Vector_iterator<std::_Vector_val<std::_Simple_types<float>>>>(Iterator,Iterator,T,T)' being compiled
1> with
1> [
1> Iterator=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<float>>>,
1> T=int
1> ]
1>c:\users\mtunca\documents\esd\sps\fractalcarpet\main.cpp(34): error C2672: 'generate': no matching overloaded function found
1>c:\users\mtunca\documents\esd\sps\fractalcarpet\main.cpp(34): error C2780: 'void std::generate(_FwdIt,_FwdIt,_Fn0)': expects 3 arguments - 2 provided
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\algorithm(1532): note: see declaration of 'std::generate'
Could someone help me, how to solve this problem?
std::generate needs a generator, something that can be called like gen().
You could create one with a lambda, perhaps like this:
template<template <typename> class Pred, typename T, typename Iterator>
void iota_stepa(Iterator begin, Iterator end, T startofSequence_, T threadStep)
{
bool first = true;
T current;
auto gen = [&]() -> T
{
if(first) {
current = startofSequence_;
first = false;
} else {
current = Pred<T>() ( current, threadStep );
}
return current;
};
generate(begin, end, gen );
}
Pred<T>(currMaxThreads, threadStep) );
Pred<T> is a type. You need to construct an actual callable object:
Pred<T>()(currMaxThreads, threadStep) );
This however cannot be the last argument to std::generate. The latter requires a callable object with no arguments, presumably holding a state (otherwise a call to std::fill woud suffice). It is unclear how an arbitrary binary function could be adapted to fill this role.
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)
I've got a type IVector3 provided by the glm library:
using IVector3 = glm::ivec3;
I've got a hash function for IVector3s:
struct IVector3Hash
{
std::size_t operator()(IVector3 const& i) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, i.x);
boost::hash_combine(seed, i.y);
boost::hash_combine(seed, i.z);
return seed;
}
};
And I'm trying to map IVector3s to floats in an unordered_map:
std::unordered_map<IVector3, float, IVector3Hash> g_score;
However, when I try and emplace a value in this map, I get a warning that I need to see the reference to function template instantiation:
g_score.emplace(from_node->index, 0);
1>c:\users\accou\documents\pathfindingexamples\c++ library\pathfindinglib\pathfindinglib\pathfinding.cpp(44): note: see reference to function template instantiation 'std::pair<std::_List_iterator<std::_List_val<std::_List_simple_types<_Ty>>>,boo
l> std::_Hash<std::_Umap_traits<_Kty,float,std::_Uhash_compare<_Kty,_Hasher,_Keyeq>,_Alloc,false>>::emplace<IVector3&,int>(IVector3 &,int &&)' being compiled
1> with
1> [
1> _Ty=std::pair<const IVector3,float>,
1> _Kty=IVector3,
1> _Hasher=IVector3Hash,
1> _Keyeq=std::equal_to<IVector3>,
1> _Alloc=std::allocator<std::pair<const IVector3,float>>
1> ]
I've looked through the documentation for std::pair and std::unordered_map but I can't see what I'm doing wrong. The code compiles, but I don't want errors to occur if other compilers are used.
Thank you for any help :)
EDIT to include full warning text: https://pastebin.com/G1EdxKKe
I was confused by the long-winded error output, but the actual error was because I was trying to emplace(...) using an int rather than a float as the map required.
Changing to:
g_score.emplace(from_node->index, 0.0f);
solved the issue.
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*)
I was hoping to create a variadic template function which sits in front of the QtConcurrent::run functions that does some stuff and then passes the parameters on.
QtConcurrent::run is massively overloaded - check out qtconcurrentrun.h
Is it possible to create a variadic template function that I can call which will pass through to QtConcurrent::run ? This is what I have thus far:
template <typename returnT, typename... Args>
static auto Run(Args&&... args) -> QFuture<returnT>
{
// Do Stuff
// Now call through to start the task
QFuture<returnT> future = QtConcurrent::run(std::forward<Args>(args)...);
QFutureWatcher<void>* futureWatcher = new QFutureWatcher<void>(); //A QFutureWatcher<void> is special, see QFutureWatcher QT docs.
futureWatcher->setFuture(future);
QObject::connect(futureWatcher, &QFutureWatcher<void>::finished, [=]() {
// Do stuff
futureWatcher->deleteLater();
});
return future;
}
I'm struggling to work out how to deduce the return type, so I've got the returnT as a separate template param. This doesn't compile (VS2012 Nov CTP) when called with:
Tasking::TaskManager::Run<void>([&]() { while (stopTask == false); });
With the top couple error messages being:
1> error C2065: '<lambda_86e0f4508387a4d4f1dd8316ce3048ac>' : undeclared identifier
1> Implementation\TaskingTests\TaskManagerTests.cpp(31) : see reference to function template instantiation 'QFuture<void> Tasking::TaskManager::Run<void,TaskManagerTests::WaitsForTaskTest::<lambda_86e0f4508387a4d4f1dd8316ce3048ac>>(TaskManagerTests::WaitsForTaskTest::<lambda_86e0f4508387a4d4f1dd8316ce3048ac> &&)' being compiled
1>C:\tkbt\Launch2.0.0\ICDE\IceLibrary\Implementation\Tasking/TaskManager.hpp(108): error C2974: 'std::forward' : invalid template argument for '_Ty', type expected
1> C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\type_traits(1780) : see declaration of 'std::forward'
1> C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\type_traits(1774) : see declaration of 'std::forward'
1>C:\tkbt\Launch2.0.0\ICDE\IceLibrary\Implementation\Tasking/TaskManager.hpp(108): error C2780: 'QFuture<T> QtConcurrent::run(const Class *,T (__cdecl Class::* )(Param1,Param2,Param3,Param4,Param5) const,const Arg1 &,const Arg2 &,const Arg3 &,const Arg4 &,const Arg5 &)' : expects 7 arguments - 0 provided
1> c:\qt\qt5.0.2\5.0.2\msvc2012_64\include\qtconcurrent\qtconcurrentrun.h(333) : see declaration of 'QtConcurrent::run'
Any help much appreciated.
I guess that TaskManager.hpp(108) is the line where you call QtConcurrent::run.
What you are experiencing seems to be this MSVC bug. In short, variadic templates cannot forward lambdas in MSVC. You probably will have to use an oldscool functor in this case or provide nonvariadic overloads to support lambdas, maybe for the first few arguments. If I had to guess I'd think QtConcurrent::run's first argument has to be a function and the other arguments are its parameters, meaning you never get to call Run without arguments. You could rewrite your function template to have one fixed "normal" parameter for the function and the parameter pack for the function arguments.
For the return type deduction you might want to use decltype. Together that would look like this:
template <class F, class... Args>
static auto Run(F&& f, Args&&... args)
-> decltype(QtConcurrent::run(std::forward<F>(f), std::forward<Args>(args)...))
{
auto future = QtConcurrent::run(std::forward<F>(f), std::forward<Args>(args)...);
//I suppose this can not be a smart pointer?
auto futureWatcher = new QFutureWatcher<void>();
futureWatcher->setFuture(future);
QObject::connect(futureWatcher, &QFutureWatcher<void>::finished, [=]() {
// Do stuff
futureWatcher->deleteLater();
});
return future;
}
This way, the lambda would be passed to the normal template parameter F, wich should be ok for forwarding, i.e. the bug should not happen this way.
Update: If QtConcurrent::run does not give you the correct return type right away, you could go by using decltype on the function and its arguments:
static auto Run(F&& f, Args&&... args)
-> QtFuture<decltype(f(std::forward<Args>(args)...))>
Maybe you'll need to add some std::remove_reference and std::remove_const to the decltype to get the right future type.
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);
}