C++ variable as a template parameter - c++

Is it possible to use variable as template parameter without switch or if else statements for each possible value?
enum A {a, b, c, d};
template<A> void f() {/* default */};
template<> void f<A::a>() {/* ... */}
template<> void f<A::b>() {/* ... */}
template<> void f<A::c>() {/* ... */}
void execute(A action) {
f<action>()
}
I could use switch statement.
void execute(A action) {
switch (action) {
case A::a:
f<A::a>();
break;
case A::b:
f<A::b>();
break;
case A::c:
f<A::c>();
break;
}
}
Or I could add function pointers to a map and use this map afterwards.
std::map<A, void(*)()> mp = {
{A::a, f<A::a>},
{A::b, f<A::b>},
{A::c, f<A::c>}
};
void execute(A action) {
mp[action]()
}
But both of these solutions require me to specify the mapping manually.
Is there a way of calling function based on a variable? Maybe using macro with function definition, or using template metaprogramming.

You can sort-of do what you want, but it only works if the value of action is known at compile-time. i.e.:
#include <stdio.h>
enum A {a, b, c, d};
template<A> void f() {}
template<> void f<A::a>() {printf("f<A::a>() called\n");}
template<> void f<A::b>() {printf("f<A::b>() called\n");}
template<> void f<A::c>() {printf("f<A::c>() called\n");}
template<A action> void execute() {
f<action>();
}
int main(int, char**)
{
constexpr A actionA = A::a;
constexpr A actionB = A::b;
constexpr A actionC = A::c;
execute<actionA>();
execute<actionB>();
execute<actionC>();
return 0;
}
.... yields this output:
$ g++ temp.cpp -std=c++11
$ ./a.out
f<A::a>() called
f<A::b>() called
f<A::c>() called
If you don't/can't know what value action is supposed to have during compilation, then templates are not the right tool for the job, because all the "which-templated-function-should-be-called-here" decisions are made at compile-time.

Related

Can I hide implementation details of this concept from the end user?

I have looked at several similar questions on SO. Maybe I am not grokking the solutions there. In those questions when the return type is auto or templated then separating declaration and definition in two different units causes a failure in compilation. This can be solved by explicitly declaring a concrete signature for the function definition. In my case I am not sure how to do that.
My scenario is as below:
// api.h
template <typename TImpl>
concept IsAProcessor = requires(TImpl impl)
{
impl.init();
impl.process();
impl.deinit();
};
enum UseCase {
USECASE1,
USECASE2
};
template <IsAProcessor TImpl>
void Process(TImpl& impl)
{
impl.process();
}
class Engine
{
public:
IsAProcessor auto getInstance(UseCase a);
};
// End - api.h
// api.cpp
#include "api.h"
#include "third_party.h"
IsAProcessor auto Engine::getInstance(UseCase a) {
switch (UseCase) {
case USECASE1:
return UseCase1Impl(); // Defined in third_party.h and satisfies concept requirement.
case USECASE2:
return UseCase2Impl();
}
}
// End - api.cpp
// third_party.h
class UseCase1Impl {
public:
void init(void);
void process(void);
void deinit(void);
}
// End - third_party.h
// third_party.cpp
#include "third_party.h"
void UseCase1Impl::init(void) {...};
// and so forth
// End - third_party.cpp
// User code
#include "api.h"
{
auto en = Engine();
auto usecase = en.getInstance(UseCase::USECASE1);
//^^^ cannot be used before it is defined here
Process(usecase);
}
As I mentioned in the question, it is not desirable to expose UseCase1Impl and UseCase2Impl. How do I get past the error: function 'getInstance' with deduced return type cannot be used before it is defined
The return type of a function is a static property, it can't change based on runtime data.
If you can, lift UseCase to a template parameter, and use if constexpr to have exactly one active return for each instantiation.
template<UseCase a>
auto Engine::getInstance() {
if constexpr (a == USECASE1)
return UseCase1Impl(); // Defined in third_party.h and satisfies concept requirement.
if constexpr (a == USECASE2)
return UseCase2Impl();
}
If you can't do that, you will have to find a common type to return.
struct IProcessor
{
virtual ~IProcessor() = default;
virtual void init() = 0;
virtual void process() = 0;
virtual void deinit() = 0;
};
template <IsAProcessor T>
class ProcessorFacade : public IProcessor
{
T impl;
public:
template <typename... Args>
ProcessorFacade(Args&&... args) : impl(std::forward<Args>(args)...) {}
void init() final { impl.init(); }
void process() final { impl.process(); }
void deinit() final { impl.deinit(); }
};
std::unique_ptr<IProcessor> Engine::getInstance(UseCase a) {
switch (UseCase) {
case USECASE1:
return std::make_unique<ProcessorFacade<UseCase1Impl>>();
case USECASE2:
return std::make_unique<ProcessorFacade<UseCase2Impl>>();
}
}

Default argument with template in C++

I'm designing an interface, by which users can define a class that tells what they want to do.
The code is something like the following,
#include <stdio.h>
class Dummy{
public:
void do(){ printf("do nothing\n"); }
};
class Task{
public:
void do(){ printf("do something\n"); }
};
template <class TASK>
void func(TASK &task = Dummy()){
task.do();
}
int main(){
func(); // do nothing
Task task;
func(task); // do something
}
How to make it work?
The main issue is this func argument:
TASK &task = Dummy()
It will not work unless it is const. This happens because non-const lvalue reference to type cannot bind to a temporary.
But if you can use const there, you can easily solve your problem:
class Dummy{
public:
void doit() const { printf("do nothing\n"); }
};
class Task{
public:
void doit() const { printf("do something\n"); }
};
template <class TASK = Dummy>
void func(const TASK &task = TASK()){
task.doit();
}
int main(){
func(); // do nothing
Task task;
func(task); // do something
}
For starters, don't have an identifier (function named) named do, since do is a language keyword. Using it as an identifier is a diagnosable error. There's no option other than changing the name of the function.
Second, the argument will of func() will need to be const, since the default value being passed is a temporary (which can only be bound to a const reference). This also means your function in the classes needs to be const qualified.
Third, when calling func() it is necessary to either pass SOME information so the compiler can work out how to instantiate the template. If you want to pass no information at all at the call site (i.e. func()) then you need to have a non-templated overload.
Fourth, use C++ streams rather than C I/O.
class Dummy
{
public:
void do_it() const { std::cout << "do nothing\n"; }
};
class Task
{
public:
void do_it() const { std::cout << "do something\n"; }
};
template <class TASK>
void func(const TASK &task)
{
task.do_it();
}
void func()
{
func(Dummy());
}
int main()
{
func(); // do nothing
Task task;
func(task); // do something
}
Option 2 is to replace the two versions of func() above with
template <class TASK = Dummy>
void func(const TASK &task = TASK())
{
task.do_it();
}

Extracting a parameter from a function passed as parameter

I have a following function:
void Class1::MainThreadFunction(const __int64 param) {
if(GetCurrentThreadId() != System::MainThreadID) {
RunInMainThread(MainThreadFunction, param);
return;
}
//...
}
void Class2::RunInMainThread(void(__closure* FuncToCall)(const __int64 ParToExtract),
const __int64 fP1) {
struct {
__int64 P1;
void(__closure* F)(const __int64);
void __fastcall FTC() { F(P1); }
} Args = {fP1, FuncToCall};
TThread::Synchronize(NULL, &Args.FTC);
}
So what I am attempting to do is to extract the first parameter in FuncToCall which is named ParToExtract above to be used for initializing the Args structure. In other words the P1 in the struct should receive the const __int64 from the passed function which is named as ParToExtract.
The above works but I currently as a workaround pass the parameter as fP1 which I use to initialize P1 but there surely must be a better way to do this.
Additional bonus would be to have the variable number of function parameters in RunInMainThread (but I have for the moment to avoid C++11 <functional>).
Please no lambda-based (or C++11 features) - this is another thing I cannot yet use for the moment.
What you already have is the correct (and only) way to approach this situation in C++Builder's "classic" (pre-C++11) compilers.
In order to support a variable number of parameters, you will have to use multiple overloads, there is no other option (without delving into low-level inline assembly to setup call stacks manually, but even then it may not work correctly across thread boundaries), eg:
void Class1::MainThreadFunction()
{
if (GetCurrentThreadId() != System::MainThreadID)
{
RunInMainThread(MainThreadFunction);
return;
}
//...
}
void Class1::MainThreadFunction(const __int64 param)
{
if(GetCurrentThreadId() != System::MainThreadID)
{
RunInMainThread(MainThreadFunction, param);
return;
}
//...
}
// and so on as needed ...
template<typename FuncType>
void Class2::RunInMainThread(FuncType FuncToCall)
{
struct {
FuncType F;
void __fastcall FTC() { F(); }
} Args = {FuncToCall};
TThread::Synchronize(NULL, &Args.FTC);
}
template<typename FuncType, typename ParamType>
void Class2::RunInMainThread(FuncType FuncToCall, const ParamType param)
{
struct {
const ParamType &P;
FuncType F;
void __fastcall FTC() { F(P); }
} Args = {param, FuncToCall};
TThread::Synchronize(NULL, &Args.FTC);
}
template<typename FuncType, typename ParamType1, typename ParamType2>
void Class2::RunInMainThread(FuncType FuncToCall, const ParamType1 param1, const ParamType2 param2)
{
struct {
const ParamType1 &P1;
const ParamType2 &P2;
FuncType F;
void __fastcall FTC() { F(P1, P2); }
} Args = {param1, param2, FuncToCall};
TThread::Synchronize(NULL, &Args.FTC);
}
// and so on as needed...
If you look through various RTL header files, such as sysvari.h and utilcls.h, using overloads is how Borland itself approaches the issue of variable number of parameters in several of its own APIs, sometimes upwards of 30+ parameters, which is more than enough to handle most user code.
The signature for the method called by TThread::Synchronize() must match the TThreadMethod type:
void __fastcall (__closure *TThreadMethod)(void);
So you can't pass parameters through it directly. Instead of going through a proxy function, use a lambda:
void MainThreadFunction(int64_t param) {
if(GetCurrentThreadId() != System::MainThreadID)
TThread::Synchronize(nullptr, [&param]{ MainThreadFunction(param); } );
//...
}
In order to have a variable number of parameters, you could make it a function template:
template< class... Args >
void MainThreadFunction(Args&&... args) {
if(GetCurrentThreadId() != System::MainThreadID)
TThread::Synchronize(nullptr, [&args...] {
MainThreadFunction(std::forward<Args>(args)...);
}
);
//...
}
When using a classic (pre C++11) compiler, you'd usually use a class private variable to carry the information.

Copy-construct and later access arbitrary POD types

I'd like to fill in the store() and launch() methods in the below code. The important detail which captures the spirit of the problem is that the object foo declared in main() no longer exists at the time we call launch(). How can I do this?
#include <cstdio>
#include <cstring>
#include <type_traits>
template<typename T, typename U=
typename std::enable_if<std::is_trivially_copyable<T>::value,T>::type>
struct Launchable {
void launch() { /* some code here */ }
T t;
// other members as needed to support DelayedLauncher
};
class DelayedLauncher {
public:
template<typename T>
void store(const Launchable<T>& t) {
// copy-construct/memcpy t into some storage
}
void launch() const {
// call t.launch(), where t is (a copy of) the last value passed into store()
}
// other members as needed
};
int main() {
DelayedLauncher launcher;
{
Launchable<int> foo;
launcher.store(foo);
}
launcher.launch(); // calls foo.launch()
return 0;
}
Note that if we only had a fixed set of N types to pass into store(), we could achieve the desired functionality by declaring N Launchable<T> fields and N non-template store() methods, one for each type, along with an enum field whose value is use in a switch statement in the launch() method. But I'm looking for an implementation of DelayedLauncher that will not need modification as more Launchable types are added.
using std::function:
class DelayedLauncher {
public:
template<typename T>
void store(const Launchable<T>& t) {
f = [t]() {t.launch();};
}
void launch() const { f(); }
private:
std::function<void()> f;
};
You could give Launchable a base class with a virtual launch() and no template, and store pointers to that base class in Launcher::store.
EDIT: Adapted from #dshin's solution:
struct LaunchableBase {
virtual void launch() = 0;
};
template<typename T, typename U=
typename std::enable_if<std::is_trivially_copyable<T>::value,T>::type>
struct Launchable : public LaunchableBase {
virtual void launch() override { /* some code here */ }
T t;
// other members as needed to support DelayedLauncher
};
class DelayedLauncher {
public:
template<typename T>
void store(const Launchable<T>& t) {
static_assert(sizeof(t) <= sizeof(obj_buffer),
"insufficient obj_buffer size");
static_assert(std::is_trivially_destructible<T>::value,
"leak would occur with current impl");
p = new (obj_buffer) Launchable<T>(t);
}
void launch() const {
p->launch();
}
private:
char obj_buffer[1024]; // static_assert inside store() protects us from overflow
LaunchableBase *p;
};
I believe this variant of Jarod42's solution will avoid dynamic allocation, although I would appreciate if someone could confirm that this will work the way I think it will:
class DelayedLauncher {
public:
template<typename T>
void store(const Launchable<T>& t) {
static_assert(sizeof(t) <= sizeof(obj_buffer),
"insufficient obj_buffer size");
static_assert(std::is_trivially_destructible<T>::value,
"leak would occur with current impl");
auto p = new (obj_buffer) Launchable<T>(t);
auto ref = std::ref(*p);
f = [=]() {ref.get().launch();};
}
void launch() const {
f();
}
private:
char obj_buffer[1024]; // static_assert inside store() protects us from overflow
std::function<void()> f;
};
I believe it should work because the resources I've looked at indicate that std::function implementations typically have a "small capture" optimization, only triggering a dynamic allocation if the total size of the captured data exceeds some threshold.
EDIT: I replaced my code with a version provided by Jarod42 in the comments. The standard guarantees the above implementation will not trigger dynamic allocation.

Conditionally initialize a struct field - only if it exists in that struct

Working on something like a unit testing framework for a very simple API:
extern "C" void execute_command(int cmd, void *params);
Which casts the params to the appropriate struct based on the cmd argument. I can't change that interface, nor can I modify the header which specifies the commands and the different param structures (which are all POD).
I do have access to an array of something like:
{ 0 /*cmd number*/, "PARAM_STRUCT_FOR_CMD_0", sizeof(PARAM_STRUCT_FOR_CMD_0) }
These param structs have some common properties. For example, many of them have a field like void *pObject;, though it is not always the same offset. To illustrate, suppose there are three structures:
struct {
void *pObject;
int someData;
} PARAM_STRUCT_FOR_CMD_0;
struct {
float someFloatData;
void *pObject;
} PARAM_STRUCT_FOR_CMD_1;
struct {
float someFloatData;
void *pAnotherObject;
} PARAM_STRUCT_FOR_CMD_2;
These two pObject fields represent the same thing, while pAnotherObject is unrelated.
Now, on to what I actually want: I'd like to cast a void* to some struct, based on cmd, and set its pObject field, if it exists in that struct. Ideally, I'd be able to do something like:
void *pGlobalObject;
void execcmd(int cmd)
{
static uint8_t params[MAX_SIZE_OF_PARAM_STRUCT];
memset(params, 0, MAX_SIZE_OF_PARAM_STRUCT);
INIT_STRUCT_IF_POSSIBLE(cmd, (void*)params);
execute_command(cmd, params);
}
Where INIT_STRUCT_IF_POSSIBLE could be something like:
#define INIT_STRUCT_IF_POSSIBLE(cmd, str) \
do { \
switch (cmd) \
{ \
case 0: static_cast<PARAM_STRUCT_FOR_CMD_0*>(str)->pObject = pGlobalObject; break; \
case 1: static_cast<PARAM_STRUCT_FOR_CMD_1*>(str)->pObject = pGlobalObject; break; \
case 2: /* nothing, no pObject field */ break; \
} \
} while (0)
except that isn't really scalable. I have ~1000 possible commands, and let's say 5 fields which I'd like to set (no struct has all 5), and new commands can be added, so I'd like to avoid manually changing this.
The obvious solution is an extra build step that parses all the structs, and creates their initializers. Adding this extra build step is a lot of pain though, due to how the project is structured, so I'm hoping for a pure C++ solution.
If there's a way to generate the initializers using the C preprocessor, I'm all for it. If it can somehow be done using templates, just as good. I have boost and C++11 available, if it helps.
One thing that would solve this is the designated initializers, such as STR x = {.pObject = pGlobalObject; };. Unfortunately, they cause an error when the field is not available. Any way to just ignore nonexistent fields? (Yes, I know they are C only, not C++, but I can switch to C if needed)
Welcome to the world of SFINAE
template<typename T>
typename std::enable_if<
std::is_same<decltype(T::pObject), void*>::value
>::type setPobject(T *t) {
t->pObject = pGlobalObject;
}
void setPobject(void *t) { }
template<typename T>
typename std::enable_if<
std::is_same<decltype(T::someFloatData), float>::value
>::type setSomeFloatData(T *t) {
t->someFloatData = someGlobalFloat;
}
void setSomeFloatData(void *t) { }
// ...
Just call them for all your objects with the correct types and they will figure out whether they apply or not themselfs. You can also automate the casting
template<typename D>
struct Call {
static void call(void *t) {
setPobject(static_cast<D*>(t));
setSomeFloatData(static_cast<D*>(t));
}
};
// desginated initializers here for convenience (non-C++)
void (* const table[])(void*) = {
[0] = Call<PARAM_STRUCT_FOR_CMD_0>::call,
[1] = Call<PARAM_STRUCT_FOR_CMD_1>::call
// ...
};
With some SFINAE you can detect the member and (type) dispatch assignment accordingly:
#include <iostream>
#include <type_traits>
// Member variable detection
// =========================
template<typename T, typename = void>
struct has_pObject : std::false_type { };
template<typename T>
struct has_pObject<T, decltype(std::declval<T>().pObject, void())> : std::true_type { };
// Optional member variable assignment
// ===================================
namespace Detail
{
template <typename T>
void assign_pObject(T& object, void* p, std::false_type) {}
template <typename T>
void assign_pObject(T& object, void* p, std::true_type) {
object.pObject = p;
}
}
template <typename T>
void assign_pObject(T& object, void* p) {
Detail::assign_pObject(object, p, has_pObject<T>());
}
// Test
// ====
struct {
void *pObject = nullptr;
int someData = 0;
} PARAM_STRUCT_FOR_CMD_0;
struct {
float someFloatData = 0;
void *pObject = nullptr;
} PARAM_STRUCT_FOR_CMD_1;
struct {
float someFloatData = 0;
void *pAnotherObject = nullptr;
} PARAM_STRUCT_FOR_CMD_2;
int main()
{
int object;
assign_pObject(PARAM_STRUCT_FOR_CMD_0, &object);
assign_pObject(PARAM_STRUCT_FOR_CMD_1, &object);
assign_pObject(PARAM_STRUCT_FOR_CMD_2, &object);
std::cout << PARAM_STRUCT_FOR_CMD_0.pObject << '\n';
std::cout << PARAM_STRUCT_FOR_CMD_1.pObject << '\n';
std::cout << PARAM_STRUCT_FOR_CMD_2.pAnotherObject << '\n';
return 0;
}