I have written a sequential version of a program, and want to parallel it with thrust-CUDA. Notice that these two versions of code are very similar (like std::vector, thrust::device_vector, thrust::host_vector), I wonder how can I manage these codes such that user can choose either version at run time while avoiding duplication?
Thanks.
You could template your code on the type of vector you are using and write explicit specialisations to perform operations specific to the type.
#include <iostream>
#include <vector>
struct other_vector { };
template<typename T> struct SpecificImplementation;
template<> struct SpecificImplementation<other_vector>
{
void SpecificWork() { std::cout << "other_vector specific work\n"; }
};
template<> struct SpecificImplementation<std::vector<int>>
{
void SpecificWork() { std::cout << "std::vector<int> specific work\n"; }
};
template<typename T>
struct GeneralImplementation : public SpecificImplementation<T>
{
void CommonWork() { std::cout << "common work\n"; }
void Run() { this->SpecificWork(); CommonWork(); }
};
int main()
{
GeneralImplementation<other_vector> i1;
i1.Run();
GeneralImplementation<std::vector<int>> i2;
i2.Run();
//GeneralImplementation<int> i3; <-- will not compile without implementation
return 0;
}
Live Example
Related
Consider this snippet:
struct A {
template <typename T> void bar(const T &) {
/*
I would like to write something like:
if constexpr(type T already processed/T is already present in typelist)
...do something fancy
else if constexpr(type T not processed/T is not present in typelist)
*/
}
};
struct Msg1 {};
struct Msg2 {};
int main() {
A a;
a.bar(Msg1{});
a.bar(Msg1{});
}
Demo
Is it possible to see at compile time for which types the method bar was already instantiated?
Ideally, there would be some kind of growing typelist, where one can check at compile time for which types bar is already instantiated.
No. It is not possible to do so at compile time. However, it would be possible to do the following at runtime:
#include <typeindex>
#include <type_traits>
#include <unordered_set>
struct A {
private:
std::unordered_set<std::type_index> already_processed_ts;
public:
template<typename T>
void bar(const T&){
if(already_processed_ts.find(typeid(T)) != already_processed_ts.end())
std::cout << "Already processed " << typeid(T).name() << std::endl;
else{
already_processed_ts.insert(typeid(T));
std::cout << "Processing " << typeid(T).name() << "... \n";
}
}
}
struct Msg{};
int main()
{
f(Msg{}); // Prints "Processing 3Msg..." (at least on my compiler)
f(Msg{}); // Prints "Already processed 3Msg"
return 0;
}
I've got a problem with a circular dependecy in C++ template methods. I realize there are several similar threads here but they didn't help me with my specific case. This here is a nonsensical example, but it illustrates the issue:
main.cpp
#include "A.h"
int main()
{
float f = 10;
A a;
a.foo( f );
}
A.h
#pragma once
#include "B.h"
#include <iostream>
class A
{
private:
B _b;
public:
A() {}
std::string getName() const { return "A"; }
template<typename T> void foo( T t )
{
if( _b.getActive() )
_b.foo( t, this );
else
std::cout << "A, " << t << std::endl;
}
};
B.h
#pragma once
#include "A.h"
#include <string>
#include <iostream>
class A;
class B
{
private:
bool _active;
public:
B() : _active( false ) {}
bool getActive() const { return _active; }
void setActive( bool active ) { _active = active; }
template<typename T> void foo( T t, const A *a )
{
std::cout << "B, " << a->getName() << std::endl;
}
};
In B.h I can neither forward-declare A (will get error C2039: 'getName': is not a member of 'A'), nor include A.h (will get error C4430: missing type specifier - int assumed.).
Is there a way around this or do I have to completely refactor my code?
EDIT
I'm compiling with MSVC 141 (VS 2017) with /std:c++latest, btw.
The problem here is that getName() in a->getName() is a non-dependent name (it does not depend on the template parameter T), and it is resolved at the point of template definition. But A is incomplete at that point.
As a simple but ugly workaround, we can introduce a fake dependency on T:
template<class T, class S>
struct First {
using Type = T;
};
struct A;
struct B {
template<typename T>
void foo(T t, const typename First<A, T>::Type* a) {
std::cout << "B, " << a->getName() << std::endl;
}
};
A cleaner solution is to move foo() definitions outside classes and include them after both A and B:
// A.h
#pragma once
#include "B.h"
class A {
// ...
template<typename T>
void foo(T t);
};
// A_impl.h
#pragma once
#include "A.h"
template<typename T>
void A::foo(T t) {
// ...
}
// Similar for B.h and B_impl.h
// main.cpp
#include "A_impl.h"
#include "B_impl.h"
int main() {
float f = 10;
A a;
a.foo(f);
}
I'd also like to add a (not so nice) solution, but maybe it's helpful for some:
during investigations it struck me that I had a different project using the same code base which does compile without any issues. I noticed the difference was the new project had the Conformance Mode set to /permissive-, while the old one had not. So if you need a quick solution for MSVC and don't care about standard conformance, you may want to turn this option off. This way, the above code works just as posted.
EDIT
Disclaimer: be aware though that this may break code, as Evg points out in the comment below.
I wonder what is the preferred C++ way for the generation of method prototypes,
when using template specialization? The technique I'm after
should scale well with the number of the foo class methods, see below.
The marked block of the reproducer has to be replaced.
Please no code snippets managed by hand or by a script.
Some additional small modifications (perhaps in the header) might be possible.
For brevity the templated class A is placed beside the typedef for Aint.
CRTP solutions are disfavored. Usage of C++17 (not later) is allowed.
Has to compile with VS2019 recent g++ and clang++.
Edit 2020-02-09:
Removing the marked block all together,
this compiles fine with
Compiler Explorer's x64 MSVC 19.14 compiler.
So do we have a compiler issue here for g++ and clang++?
// begin of testspec.h
template<class T>
class A
{
public:
A();
void foo1();
void foo2();
void foo3();
};
typedef A<int> Aint;
// end of testspec.h
// begin of testspec.cpp
#include "testspec.h"
#include <iostream>
/////////////// can this block be simplified? //////////
template<>
void
A<int>::foo1();
template<>
void
A<int>::foo2();
template<>
void
A<int>::foo3();
/////////////// can this block be simplified? //////////
template<>
A<int>::A()
{
foo1();
foo2();
foo3();
std::cout << "hello world" << std::endl;
}
template<>
void
A<int>::foo1()
{
std::cout << "foo1" << std::endl;
}
template<>
void
A<int>::foo2()
{
std::cout << "foo2" << std::endl;
}
template<>
void
A<int>::foo3()
{
std::cout << "foo3" << std::endl;
}
// end of testspec.cpp
// begin of main.cpp
#include "testspec.h"
int main()
{
Aint a;
return 0;
};
// end of main.cpp
Assuming that there is a part of A that does not get specialized, then the portion of A that you are trying to allow for modifiable behavior via specialization can be accomplished by adopting a policy pattern.
class APolicy {
template <class, class> friend class A;
void foo1 ();
void foo2 ();
void foo3 ();
};
template <class T, class P = APolicy>
class A {
void foo1() { P().foo1(); }
void foo2() { P().foo1(); }
void foo3() { P().foo1(); }
};
And then instead of specializing A<int>, you implement a policy IntPolicy, and then instantiate A<int, IntPolicy>.
I'm trying to wrap std::packaged_task inside another class in order to be used together with a task scheduler.
At the moment I got it all working except std::future support. To get std::future support I figured out I need to use std::packaged_task for the get_future() function that it provides.
I've been trying whole day all sorts of ways to get this to work, but I seem to be unable to properly declare and initialise the packaged_task using the return value from a std::bind. I have tried to decipher the implementations of all the related libstdc++ functions such as std::async, std::future, std::thread etc but with no luck.
The following code is the implementation of both the not working version and the working one. To get it to work uncomment the two /* --- WORKS*/ and comment the other related line.
#include <vector>
#include <deque>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include <iostream>
#include <chrono>
#include <functional>
#include <windows.h>
class task
{
private:
struct task_implementation_base
{
virtual void execute() = 0;
};
template <class callable>
struct task_implementation : public task_implementation_base
{
task_implementation(callable&& f) : /*m_task(std::forward<callable>(f)) WORKS*/m_task(f) { }
void execute() { m_task(); }
//callable m_task; // WORKS
std::packaged_task<typename result_of<callable>::type> m_task;
};
template <class callable>
std::shared_ptr<task_implementation<callable>> make_routine(callable&& f)
{
return std::make_shared<task_implementation<callable>>(std::forward<callable>(f));
}
public:
template <class callable, class... arguments>
task(callable&& f, arguments&&... args) : m_function(make_routine(std::bind(std::forward<callable>(f), std::forward<arguments>(args)...))) {}
void operator()() { run(); }
void run() { m_function->execute(); }
private:
std::shared_ptr<task_implementation_base> m_function;
};
int testint(int i)
{
std::cout << "test6" << " :: ran from thread " << std::this_thread::get_id() << "\n";
fflush(stdout);
return i+100;
}
void test(const char* text)
{
std::cout << text << " :: ran from thread " << std::this_thread::get_id() << "\n";
fflush(stdout);
}
class testclass
{
public:
void print1() { test("test3"); }
void print2() { test("test4"); }
void print3(const char* text) { test(text); }
};
int main()
{
testclass testclass1;
testclass* testclass2 = new testclass;
task test1(test, "test1");
task test2([]() { test("test2"); });
task test3(&testclass::print1, &testclass1);
task test4(&testclass::print2, &*testclass2);
task test5(&testclass::print3, &*testclass2, "test5");
task test6(&testint, 1);
test1();
test2();
test3();
test4();
test5();
test6();
Sleep(2000);
return 0;
}
I'm thinking the problem is typename result_of<callable>::type. I'm guessing it doesn't properly evaluates to the return type of the callable function.
I'm using c++ (Built by MinGW-builds project) 4.8.0 20121225 (experimental) on a Windows 8 64bit. I'm suspecting the errors are irrelevant since I guess I'm just simply trying to get this work the wrong way but here is a pastebin for the errors anyway: errors
std::packaged_task not only takes the result type of the invoked function as a template argument but also the types of the arguments you are passing to the to be invoked function.
You can define them as follows:
// somewhere
int foo(bool, int);
// somewhere else
std::packaged_task<int(bool, int)> p(foo);
To fix your code you need to add two empty parenthesis pairs. What I explained above also applies to std::result_of.
std::packaged_task<typename std::result_of<callable()>::type()> m_task;
It is only response to main topic question. "How to implement"
Example short implementation:
template <typename Signature> /// <---- 1
class Task;
template <typename Res, typename... ArgTypes>
class Task<Res(ArgTypes...)> /// <---- 2
{
public:
template <typename Function>
explicit Task(Function&& callback)
: _task{std::forward<Function>(callback)}
{ }
void execute(ArgTypes... args) noexcept(false)
{
//...
_task(std::forward<ArgTypes>(args)...);
}
private:
std::packaged_task<Res(ArgTypes...)> _task;
};
Not sure why step 1 & 2 are required but I did the same as in lib implementation. Maybe someone could extend this response.
Have a problem about how to call the generic template version in a specialization version.
Here is the sample code. But the "vector::push_back(a)" calls itself recursively.
#include <iostream>
#include <vector>
using namespace std;
namespace std
{
template<>
void vector<int>::push_back(const int &a)
{
cout << "in push_back: " << a << endl;
vector::push_back(a); // Want to call generic version
}
}
int main()
{
vector<int> v;
v.push_back(10);
v.push_back(1);
return 0;
}
When you create specialization for some template (no difference class of function), you tell to compiler to generate that one instead of general. So in fact if you have specialization you have no general version for that specialization and you can't call it, because it doesn't exists.
You can simply extract the code into another template function:
template<typename T>
void baseF(T t) { ... }
template<typename T>
void F(T t) { baseF<T>(t); }
template<>
void F<int>(int t) { baseF<int>(t); }
Well, to complement, I think it works for template function specification in some situations.
#include <iostream>
#include <vector>
using namespace std;
class Base
{
public:
virtual int test() {return 0;}
};
class Derived : public Base
{
public:
virtual int test() {return 1;}
};
template<class T>
void TestOutput(T* a)
{
cout << a->test() << endl;
}
template<>
void TestOutput(Derived* a)
{
cout << "something else" << endl;
TestOutput<Base>(a);
}
int main()
{
Derived d;
TestOutput(&d);
}
I compiled it with visual studio 2013 and the output is:
something else
1
Although I don't think you can always find a TestOutput function of Base to call the generic one.