Parameter pack expansion for variadic class member (tuple or other) - c++

I am trying to store a tuple of references in a class (via a variadic template), and then I want to "loop" over them and assign them values.
Function process2 below works as expected, but I want to make function process1 work the same (making use of the stored references of the class itself). However, I can't make process1 compile. What's the correct way? Is there a way to maybe have member Args&... args; instead of std::tuple<Args&...> args (as that might allow the parameter expansion)? Any suggestions appreciated.
Sample Code:
#include <tuple>
#include <string>
#include <iostream>
template<class... Args>
class Handler
{
private:
template <class T>
static bool process_arg(T& val)
{
if constexpr (std::is_same_v<T, int>)
val = 123;
else if constexpr (std::is_same_v<T, std::string>)
val = "string";
else
{
// do something
return false;
}
return true;
}
public:
const std::tuple<Args&...> args;
Handler(Args&... args)
: args(args ...) { }
// bool process1() const
// {
// // Compile Error: operand of fold expression has no unexpanded parameter packs
// const bool success = (process_arg(args) && ...);
// // Compile Error: no matching function for process_arg(int&, int&, std::string&)
// bool success = true;
// std::apply([&success](auto &&... v) { success = success && process_arg(v...); }, args);
// return success;
// }
template<class... Args2>
static bool process2(Args2&... args2)
{
const bool success = (process_arg(args2) && ...);
return success;
}
};
int main()
{
int a, b;
std::string c;
// Handler(a, b, c).process1();
Handler<>::process2(a, b, c);
std::cout << a << "," << b << "," << c << "\n";
return 0;
}

You're on the right track with std::apply but the syntax is incorrect; the pack expansion needs to be outside the call to process_arg. Also, you don't need the variable success at all; you can use a fold-expression directly:
bool process1() const
{
return std::apply([](auto &&... v) {
return (process_arg(v) && ...);
}, args);
}
Here's a demo

Not sure this is what you need, since it doesn't store anything as members. But I think it gives the desired output. O well... maybe there is something for you to take away from this :)
class Handler
{
private:
template <class T>
static bool process_arg(T& val)
{
if constexpr (std::is_same_v<T, int>)
val = 123;
else if constexpr (std::is_same_v<T, std::string>)
val = "string";
else
{
// do something
return false;
}
return true;
}
public:
template<typename arg_t, typename... args_t>
static constexpr bool process(arg_t& arg, args_t&... args)
{
if constexpr (sizeof...(args_t) > 0)
{
bool success = process_arg<arg_t>(arg) && process(args...);
return success;
}
return process_arg<arg_t>(arg);
}
};
int main()
{
int a, b;
std::string c;
Handler::process(a, b, c);
std::cout << a << "," << b << "," << c << "\n";
return 0;
}

Related

deferred selection of types during compile-time

Is there a standard way for me to select a type at compile-time in c++20 when the type depends on compile-time information available later in the function, i.e. the type is "deferred" because of intermediate compile-time dependencies.
For example something like this which depends on the auto keyword but does not compile:
template<bool value, typename ...>
struct bool_type : std::integral_constant<bool , value> {};
template<typename T>
void function(T* v) {
auto r;
bool different_type = false;
if constexpr (...)
r = (T)subfunc_a(v);
else if constexpr (...)
r = (T)subfunc_b(v);
else if constexpr (...)
r = (T)subfunc_c(v);
else if constexpr (...);
r = (T)subfunc_d(v);
else if constexpr (...)
r = (T)subfunc_e(v);
// This condition depends on previous conditions. Extracting the condition
// to the top of this function for use with `std::conditional` would be
// burdensome. Decoupling the conditional in this way also risks errors. I
// want to depend on the type system to enforce code correctness.
else if constexpr (...) {
r = (long)subfunc_f(v);
different_type = true;
}
else if constexpr (...) {
r = (unsigned long)subfunc_g(v);
different_type = true;
}
else {
static_assert(bool_type<false, T>::value, "Unsupported type");
}
do_common_work();
if (different_type)
do_more_work();
*v = r;
}
Or this example which depends on the static if proposal which prevents if constexpr conditionals from creating a new scope. The proposal didn't pass so the code doesn't compile.
template<typename T>
void function(T* v) {
bool different_type = false;
if constexpr (...)
T r = subfunc_a(v);
else if constexpr (...)
T r = subfunc_b(v);
else if constexpr (...)
T r = subfunc_c(v);
else if constexpr (...);
T r = subfunc_d(v);
else if constexpr (...)
T r = subfunc_e(v);
else if constexpr (...) {
different_type = true;
long r = subfunc_f(v);
}
else if constexpr (...) {
different_type = true;
unsigned long r = subfunc_g(v);
}
else {
static_assert(bool_type<false, T>::value, "Unsupported type");
}
do_common_work();
if (different_type)
do_more_work();
*v = r;
}
auto variable can only infer its type from the initialization expression in C++. If you don't want to explicitly specify its type, you can extract the initialization into a separate function which returns the necessary value (type is auto) and initialize with this function's call.
In particular, the extracted function can be a lambda expression, so you get an immediately invoked function expression or IIFE:
#include <iostream>
#include <type_traits>
template <bool value, typename...>
struct bool_type : std::integral_constant<bool, value> {};
template <typename T> void function(T *v) {
bool different_type = false;
auto r = [&] { // create a function
if constexpr (std::is_same_v<T, int>) {
return 10;
} else if constexpr (std::is_same_v<T, double>) {
return 10.0;
} else if constexpr (std::is_same_v<T, long>) {
different_type = true;
return 10LL;
} else {
static_assert(bool_type<false, T>::value, "Unsupported type");
}
}(); // immediately invoke the created function
std::cout << typeid(r).name() << " " << different_type << "\n";
*v = r;
}
int main() {
int a;
double b;
long c;
[[maybe_unused]] float d;
function(&a); // int 0
function(&b); // double 0
function(&c); // long long 1
// function(&d); // compilation error
}
In the code above, the lambda expression has a return type of auto, i.e. it's automatically deduced from the return chosen by if constexpr. Only a single return is chosen, so the return type is unambiguous, so r's type is also inferred correctly.

C++ variadic template empty argument specialization

What's the correct way to write a specialization for an empty argument variadic template. Take bellow code as an example:
#include <iostream>
#include <memory>
#include <tuple>
#include <functional>
#include <cassert>
using namespace std;
struct message {
int type;
};
struct X: message {
int payload;
X(): message{1} {
}
};
struct Y: message {
int payload;
Y(): message{2} {
}
};
struct Z: message {
int payload;
Z(): message{3} {
}
};
template<typename T>
constexpr int message_type = -1;
template<>
constexpr int message_type<X> = 1;
template<>
constexpr int message_type<Y> = 2;
template<>
constexpr int message_type<Z> = 3;
struct M {
int payload;
M(int payload): payload{ payload } {
}
};
template<typename P, typename T1, typename... Ts>
tuple<int, unique_ptr<M>> helper(unique_ptr<message> &msg, function<int(unique_ptr<T1>&)> fn1, function<int(unique_ptr<Ts>&)>... fn) {
if (msg->type == message_type<T1>) {
unique_ptr<T1> m(static_cast<T1*>(msg.release()));
auto result = fn1(m);
return {result, make_unique<M>(m->payload)};
} else {
return helper<void, Ts...>(msg, fn...);
}
}
template<typename P>
tuple<int, unique_ptr<M>> helper(unique_ptr<message> &msg) {
assert(false);
return {0, unique_ptr<M>()};
}
template<typename... Ts>
tuple<int, unique_ptr<M>> dispatch_msg(unique_ptr<message> &msg, function<int(unique_ptr<Ts>&)> ...fn) {
return helper<void, Ts...>(msg, fn...);
}
int main() {
auto *real_message = new Z;
real_message->payload = 101;
unique_ptr<message> msg(real_message);
auto [result, m] = dispatch_msg<X, Y, Z>(msg, [](auto &x) {
return x->payload + 1;
}, [](auto &y) {
return y->payload + 2;
}, [](auto &z) {
return z->payload + 3;
});
cout << result << '\n' << m->payload << endl;
return 0;
}
The helper function takes variadic template arguments. If it checked all given type arguments and failed. e.g. run to the empty arguments. I want to assert and stop the process.
The current code works but I'm wondering is there any straightforward way to write a specialization.
I simplified the core requirements into the code below:
template<typename T, typename... Ts>
void func(int val, T arg, Ts... args) {
if (condition_hold<T>(val)) {
return;
} else {
return func<Ts...>(val, args...);
}
}
template<>
void func(int val) {
assert(false);
}
int main() {
func<int, double, float>(100);
return 0;
}
Basically the func is checking against every given type whether a condition hold for the input val. If all check failed I want to do something, like the assert here. So I wrote a specialization takes empty argument, but this can't compile.
In C++17, you don't need to split parameter packs into head and tail in most cases. Thanks to fold expressions, many operations on packs become much easier.
// Some generic predicate.
template <typename T>
bool condition_hold(T) {
return true;
}
// Make this whatever you want.
void do_something_with(int);
template<typename... Ts>
auto func(int val, Ts... args) {
// Fold expression checks whether the condition is true for all
// elements of the parameter pack.
// Will be true if the parameter pack is empty.
if ((condition_hold(args) && ...))
do_something_with(val);
}
int main() {
// Ts type parameters are deduced to <float, float>.
func(100, 1.f, 2.f);
return 0;
}
To check whether the pack was empty and handle this case specially, you can do:
template<typename... Ts>
auto func(int val, Ts... args) {
if constexpr (sizeof...(Ts) == 0) {
// handle empty pack
}
else {
// handle non-empty pack
}
}
Your specialization couldn't have worked because func<> needs to take at least one parameter. A specialization such as
template<typename T>
void func<T>(int val);
Wouldn't be valid either, because it wold be a partial specialization which is only allowed for classes.
However, if the base template only takes a pack, we can fully specialize it:
template<typename... Ts>
void func(int val, Ts... args);
template<>
void func<>(int val);

C++ generic callback implementation

I have a code that takes messages from flash player in a form of XML parse them into function and arguments and calls a registered callback for that function.
The piece of code that I want to replace is something nicely done (almost) generic Callback mechanism:
code for the generic callback implementation of flashSDK (ASInterface.inl).
The problem with it is that this code is written for flash and I want to replace the flash and use other service that will have the same interface. Is there any standard implementation of this callback mechanism (std? boost? something else open sourced?)?
This code implements generic callbacks mechanism that you can register function with number of arguments and types in a map:
void SomethingHappened(int a, int b) {print a + b;}
void SomethingElseHappened(string abcd) {print abcd;}
callbacks["SomethingHappened"] = &SomethingHappened;
callbacks["SomethingElseHappened"] = &SomethingElseHappened;
and than search for it and call with an array of arguments:
Callbacks::iterator itCallback = callbacks.find(functionName);
if (itCallback != callbacks.end())
{
HRESULT result = itCallback->second.Call(arguments, returnValue);
}
full usage example:
//init callbacks
std::map<std::wstring, Callback> callbacks;
void SomethingHappened(int a, int b) {print a + b;}
void SomethingElseHappened(string abcd) {print abcd;}
callbacks[functionName] = &SomethingHappened;
void MessageArrived(string xmlInput)
{
string functionName = parseFunctionName(xmlInput);
Callbacks::iterator itCallback = callbacks.find(functionName);
if (itCallback != callbacks.end())
{
//parse arguments
std::vector<std::wstring> args;
_Args::split(xml, args);
ASValue::Array arguments;
for (size_t i = 0, s = args.size(); i < s; ++i)
{
ASValue arg; arg.FromXML(args[i]);
arguments.push_back(arg);
}
ASValue returnValue;
//***this is where the magic happens: call the function***
HRESULT result = itCallback->second.Call(arguments, returnValue);
return result;
}
}
You probably need a wrapper around std::function, something like:
template <typename T> struct Tag{};
// Convert ASValue to expected type,
// Possibly throw for invalid arguments.
bool Convert(Tag<Bool>, AsValue val) { return (Boolean)val; }
int Convert(Tag<int>, AsValue val) { return (Number)val; }
// ...
struct Callback
{
private:
template <std::size_t ... Is, typename Ret, typename ... Ts>
static Ret call_impl(Ret(* func)(Ts...), std::index_sequence<Is...>)
{
if (arr.size() != sizeof...(Is)) throw std::invalid_argument{};
return func(Convert(tag<Ts>{}, arr[Is])...);
}
public:
template <typename Ret, typename ... Ts>
Callback(Ret(* func)(Ts...)) : Call{[func](ASValue::Array arr, ASValue& ret)
{
try
{
ret = Callback::call_impl(func, std::make_index_sequence<sizeof(...(Ts)>());
return S_OK;
} catch (...) {
return E_INVALIDARG;
}
}}
{}
std::function<HRESULT(ASValue::Array, ASValue&)> Call;
};
std::index_sequence is C++14, but you might find implementation on SO.
You could implement something like that.
A map of objects (GenericCallback here) containing std::function<R(Args...)> objects type-erased with std::any or std::variant.
You need to be careful in the way you call your function callbacks though.
E.g. I have to feed it a std::string("hello world") and not a simple C-string, otherwise the std::any_cast will throw (since a function<string(const char*)> is not a function<string(string)>).
#include <algorithm>
#include <any>
#include <functional>
#include <iostream>
#include <string>
#include <map>
#include <memory>
struct Caller {
virtual ~Caller() = default;
virtual std::any call(const std::vector<std::any>& args) = 0;
};
template<typename R, typename... A>
struct Caller_: Caller {
template <size_t... Is>
auto make_tuple_impl(const std::vector<std::any>& anyArgs, std::index_sequence<Is...> ) {
return std::make_tuple(std::any_cast<std::decay_t<decltype(std::get<Is>(args))>>(anyArgs.at(Is))...);
}
template <size_t N>
auto make_tuple(const std::vector<std::any>& anyArgs) {
return make_tuple_impl(anyArgs, std::make_index_sequence<N>{} );
}
std::any call(const std::vector<std::any>& anyArgs) override {
args = make_tuple<sizeof...(A)>(anyArgs);
ret = std::apply(func, args);
return {ret};
};
Caller_(std::function<R(A...)>& func_)
: func(func_)
{}
std::function<R(A...)>& func;
std::tuple<A...> args;
R ret;
};
struct GenericCallback {
template <class R, class... A>
GenericCallback& operator=(std::function<R(A...)>&& func_) {
func = std::move(func_);
caller = std::make_unique<Caller_<R, A...>>(std::any_cast<std::function<R(A...)>&>(func));
return *this;
}
template <class Func>
GenericCallback& operator=(Func&& func_) {
return *this = std::function(std::forward<Func>(func_));
}
std::any callAny(const std::vector<std::any>& args) {
return caller->call(args);
}
template <class R, class... Args>
R call(Args&&... args) {
auto& f = std::any_cast<std::function<R(Args...)>&>(func);
return f(std::forward<Args>(args)...);
}
std::any func;
std::unique_ptr<Caller> caller;
};
using namespace std;
//Global functions
int sub(int a, int b) { return a - b; }
std::function mul = [](int a, int b) { return a*b;};
std::string sortString(std::string str) {
std::sort(str.begin(), str.end());
return str;
}
int main()
{
std::map<std::string, GenericCallback> callbacks;
// Adding our callbacks
callbacks["add"] = [](int a, int b) { return a + b; };
callbacks["sub"] = sub;
callbacks["mul"] = std::move(mul);
callbacks["sortStr"] = sortString;
// Calling them (hardcoded params)
std::cout << callbacks["add"].call<int>(2, 3) << std::endl;
std::cout << callbacks["sub"].call<int>(4, 2) << std::endl;
std::cout << callbacks["mul"].call<int>(5, 6) << std::endl;
std::cout << callbacks["sortStr"].call<std::string>(std::string("hello world")) << std::endl;
// Calling "add" (vector of any params)
std::vector<std::any> args = { {1}, {2} };
std::any result = callbacks["add"].callAny(args);
std::cout << "result=" << std::any_cast<int>(result) << std::endl;
return 0;
}
https://godbolt.org/z/h63job

C++ templates to avoid long switches, while calling a function with different return types

I have many functions q1, q2, q3, etc., each with a different return type (int, int64_t, std::string, etc.).
I also have a print_result function that prints out their results (and the time they take to run, but trimmed here for simplicity):
template <typename T>
void print_result(T (*func)()) {
T res = func();
std::cout << res << std::endl;
}
I also have big switch statement to print the result for each of the functions:
switch (question_num) {
case 1: print_result(q1); break;
case 2: print_result(q2); break;
case 3: print_result(q3); break;
// ...
}
Objective: I would like to replace this switch statement with a template function, to avoid copying each line every time I add a new function.
I have tried to look at C++ template instantiation: Avoiding long switches, but I'm new to template metaprogramming, so not sure how to handle this exactly.
My current attempt that doesn't compile:
template <<int, typename> ...> struct FuncList {};
template <typename T>
bool handle_cases(int, T, FuncList<>) {
// default case
return false;
}
template <<int I, typename T> ...S>
bool handle_cases(int i, T (*func)(), FuncList<T, S...>) {
if (I != i) {
return handle_cases(i, func, FuncList<S...>());
}
print_result(func);
return true;
}
template <typename ...S>
bool handle_cases(int i, T (*func)()) {
return handle_cases(i, func, FuncList<S...>());
}
// ...
bool res = handle_cases<
<1, q1>, <2, q2>, <3, q3>
>(question_num);
// ...
My ideal way of using this template is shown at the last line there.
Note that the mappings from the function number to the function is provided there. The function numbers are fixed, i.e. q1 maps to the constant 1 and that won't change at runtime.
The compilation error (it might be rather basic but I really don't know much about metaprogramming):
error: expected unqualified-id before ‘<<’ token
17 | template <<int, typename> ...> struct FuncList {};
| ^~
If you can use c++17, here's a "simplified" version of #Klaus's approach. Instead of using a had-made recursive structure, you could use a c++17 fold-expression:
template<auto... Funcs, std::size_t... I>
bool select_case(std::size_t i, std::integer_sequence<std::size_t, I...>) {
return ([&]{ if(i == I) { print_result(Funcs); return true; } return false; }() || ... );
}
template<auto... Funcs>
struct FuncSwitch {
static bool Call(std::size_t i) {
return select_case<Funcs...>(i, std::make_index_sequence<sizeof...(Funcs)>());
}
};
The idea is to wrap each of Funcs in a lambda such that only the function corresponding to the index passed is called. Note that the || in the fold expression short-circuits.
Would be used like this:
float q0() { return 0.f; }
int q1() { return 1; }
std::string q2() { return "two"; }
int main() {
bool success = FuncSwitch<q0, q1, q2>::Call(1);
}
See here for a complete example.
I've got a different proposal:
Use an std::array instead of switch (or std::map if the switch cases are non-continuous, std::array has O(1) access time, std::map O(log(n)) and switch O(n).
Use std::function and std::bind to bind your functions you want to call to a functor object
use the index into the array to call the function
Use placeholders if you need to pass additional data
#include <iostream>
#include <functional>
template <typename T>
void print_result(T (*func)()) {
T res = func();
std::cout << res << std::endl;
}
int int_function() {
return 3;
}
double double_function() {
return 3.5;
}
std::array<std::function<void()>, 2> functions({
std::bind(print_result<int>, int_function),
std::bind(print_result<double>, double_function),
});
int main() {
functions[0]();
functions[1]();
return 0;
}
Output:
3
3.5
See: Why does std::function can implicit convert to a std::function which has more parameter?
Update:
With parameter passing:
#include <iostream>
#include <functional>
template <typename T>
void print_result(T (*func)(int), int value) {
T res = func(value);
std::cout << res << std::endl;
}
int int_function(int value) {
return 3 * value;
}
double double_function(int value) {
return 3.5 * value;
}
std::array<std::function<void(int)>, 2> functions({
std::bind(print_result<int>, int_function, std::placeholders::_1),
std::bind(print_result<double>, double_function, std::placeholders::_1),
});
int main() {
functions[0](10);
functions[1](11);
return 0;
}
Output:
30
38.5
You may like a version which do not need any kind of runtime containers, did not generate any objects in between and even do not generate a data table and generates very less code and is also easy to use:
// Example functions
int fint() { return 1; }
double fdouble() { return 2.2; }
std::string fstring() { return "Hallo"; }
// your templated result printer
template < typename T>
void print_result( T parm )
{
std::cout << "The result of call is " << parm << std::endl;
}
// lets create a type which is able to hold functions
template < auto ... FUNCS >
struct FUNC_CONTAINER
{
static constexpr unsigned int size = sizeof...(FUNCS);
};
// and generate a interface to switch
template < unsigned int, typename T >
struct Switch_Impl;
template < unsigned int IDX, auto HEAD, auto ... TAIL >
struct Switch_Impl< IDX, FUNC_CONTAINER<HEAD, TAIL...>>
{
static void Do( unsigned int idx )
{
if ( idx == IDX )
{
// Your function goes here
print_result(HEAD());
}
else
{
if constexpr ( sizeof...(TAIL))
{
Switch_Impl< IDX+1, FUNC_CONTAINER<TAIL...>>::Do(idx);
}
}
}
};
// a simple forwarder to simplify the interface
template < typename T>
struct Switch
{
static void Do(unsigned int idx )
{
Switch_Impl< 0, T >::Do( idx );
}
};
// and lets execute the stuff
int main()
{
using FUNCS = FUNC_CONTAINER< fint, fdouble, fstring >;
for ( unsigned int idx = 0; idx< FUNCS::size; idx++ )
{
Switch<FUNCS>::Do(idx);
}
}
Given you "current attempt"... it seems to me that you could write a handle_cases struct/class almost as follows
struct handle_cases
{
std::map<int, std::function<void()>> m;
template <typename ... F>
handle_cases (std::pair<int, F> const & ... p)
: m{ {p.first, [=]{ print_result(p.second); } } ... }
{ }
void operator() (int i)
{ m[i](); }
};
with a map between an integer and a lambda that call print_result with the function and an operator() that call the requested lambda, given the corresponding index.
You can create an object of the class as follows (unfortunately I don't see a way to avoid the std::make_pair()s)
handle_cases hc{ std::make_pair(10, q1),
std::make_pair(20, q2),
std::make_pair(30, q3),
std::make_pair(40, q4) };
and using it as follows
hc(30);
The following is a full compiling example
#include <functional>
#include <map>
#include <iostream>
template <typename T>
void print_result (T(*func)())
{
T res = func();
std::cout << res << std::endl;
}
struct handle_cases
{
std::map<int, std::function<void()>> m;
template <typename ... F>
handle_cases (std::pair<int, F> const & ... p)
: m{ {p.first, [=]{ print_result(p.second); } } ... }
{ }
void operator() (int i)
{ m[i](); }
};
char q1 () { return '1'; }
int q2 () { return 2; }
long q3 () { return 3l; }
long long q4 () { return 4ll; }
int main ()
{
handle_cases hc{ std::make_pair(10, q1),
std::make_pair(20, q2),
std::make_pair(30, q3),
std::make_pair(40, q4) };
hc(30);
}

how to infer the return value type from std::function?

I'd like to make the return value type generic using std::function, but it does not work, code:
debuggable code can be found: http://cpp.sh/5bk5
class Test
{
public:
template <typename R, typename F = std::function<R()>>
R f(F&& op) {
op();
}
void t() {
int a = 10;
f([this, a]() { return "chars"; });
}
};
int main()
{
t::Test test;
test.t();
return 0;
}
You could avoid the Template/std::function way and use auto for return type.
If you can compile C++14 it's easy
// Example program
#include <iostream>
class Test
{
public:
Test(){ }
template <typename F>
auto f (F && op)
{ return op(); }
void t()
{ std::cout << f([this]() { return "chars"; }) << std::endl; }
};
int main()
{
Test test;
test.t();
return 0;
}
If you can compile only C++11 you have to use decltype() for Test::f()
template <typename F>
auto f (F && op) -> decltype( op() )
{ return op(); }