Deduce class template arguments from class constuctor - c++

I would like to let compiler deduce partially class template arguments from constructor.
The motivation is to write a protocol library where the existance (here the length in bits) of certain data depends of the value of last variable, so a conditional class must be used to model this.
The c++ code I want to implement should work like this, but I would like to implement it in a more expressive and simplified way, without having to set all the parameters in the template but leaving compiler deduce them:
Coliru link: https://coliru.stacked-crooked.com/a/bb15abb2a9c09bb1
#include <iostream>
template<typename T1, typename T2, typename F, int... Ints>
struct If : T1
{
const T2& condition;
constexpr If(const T2& cond) : condition(cond) {}
constexpr int bits() { return check() ? T1::bits : 0; }
constexpr bool check()
{
return (F{}(Ints, condition.value) || ...);
}
};
struct Variable1
{
int value{};
static constexpr int bits{ 5 };
};
struct Variable2
{
int value{};
static constexpr int bits{ 8 };
};
struct Datagram
{
Variable1 var1;
If<Variable2, Variable1, std::equal_to<int>, 1, 2> var2{ var1 };//It compiles and works OK under c++17. What I have...
//If<Variable2> var2{ var1, std::equal_to<int>{}, 1, 2 };// ...what I wish
};
int main()
{
Datagram data;
data.var1.value = 0;
std::cout << data.var2.bits() << "\n";//must be 0
data.var1.value = 1;
std::cout << data.var2.bits() << "\n";//must be 8
data.var1.value = 2;
std::cout << data.var2.bits() << "\n";//must be 8
}
Is this possible?

The concept you are probably looking for is "type erasure", e.g. via std::function. Something along these lines:
template<typename T1>
struct If : T1
{
std::function<bool()> checker_;
template <typename T2, typename F, typename... Args>
constexpr If(const T2& cond, F&& f, Args&&... args)
: checker_([=, &cond]() { return (f(args, cond.value) || ...); })
{}
constexpr int bits() { return check() ? T1::bits : 0; }
constexpr bool check()
{
return checker_();
}
};
Demo

Related

A type trait to detect functors using C++17?

Problem description:
C++17 introduces std::invocable<F, Args...>, which is nice to detect if a type... is invocable with the given arguments. However, would there be a way to do it for any arguments for functors (because combinations of the existing traits of the standard library already allow to detect functions, function pointers, function references, member functions...)?
In other words, how to implement the following type trait?
template <class F>
struct is_functor {
static constexpr bool value = /*using F::operator() in derived class works*/;
};
Example of use:
#include <iostream>
#include <type_traits>
struct class0 {
void f();
void g();
};
struct class1 {
void f();
void g();
void operator()(int);
};
struct class2 {
void operator()(int);
void operator()(double);
void operator()(double, double) const noexcept;
};
struct class3 {
template <class... Args> constexpr int operator()(Args&&...);
template <class... Args> constexpr int operator()(Args&&...) const;
};
union union0 {
unsigned int x;
unsigned long long int y;
template <class... Args> constexpr int operator()(Args&&...);
template <class... Args> constexpr int operator()(Args&&...) const;
};
struct final_class final {
template <class... Args> constexpr int operator()(Args&&...);
template <class... Args> constexpr int operator()(Args&&...) const;
};
int main(int argc, char* argv[]) {
std::cout << is_functor<int>::value;
std::cout << is_functor<class0>::value;
std::cout << is_functor<class1>::value;
std::cout << is_functor<class2>::value;
std::cout << is_functor<class3>::value;
std::cout << is_functor<union0>::value;
std::cout << is_functor<final_class>::value << std::endl;
return 0;
}
should output 001111X. In an ideal world, X should be 1, but I don't think it's doable in C++17 (see bonus section).
Edit:
This post seems to present a strategy that solves the problem. However, would there be a better/more elegant way to do it in C++17?
Bonus:
And as a bonus, would there be a way to make it work on final types (but that's completely optional and probably not doable)?
Building on my answer to my answer to this qustion, i was able to solve your problem, including the bonus one :-)
The following is the code posted in the other thread plus some little tweaks to get a special value when an object can't be called. The code needs c++17, so currently no MSVC...
#include<utility>
constexpr size_t max_arity = 10;
struct variadic_t
{
};
struct not_callable_t
{
};
namespace detail
{
// it is templated, to be able to create a
// "sequence" of arbitrary_t's of given size and
// hece, to 'simulate' an arbitrary function signature.
template <size_t>
struct arbitrary_t
{
// this type casts implicitly to anything,
// thus, it can represent an arbitrary type.
template <typename T>
operator T&& ();
template <typename T>
operator T& ();
};
template <typename F, size_t... Is,
typename U = decltype(std::declval<F>()(arbitrary_t<Is>{}...))>
constexpr auto test_signature(std::index_sequence<Is...>)
{
return std::integral_constant<size_t, sizeof...(Is)>{};
}
template <size_t I, typename F>
constexpr auto arity_impl(int) -> decltype(test_signature<F>(std::make_index_sequence<I>{}))
{
return {};
}
template <size_t I, typename F, std::enable_if_t<(I == 0), int> = 0>
constexpr auto arity_impl(...) {
return not_callable_t{};
}
template <size_t I, typename F, std::enable_if_t<(I > 0), int> = 0>
constexpr auto arity_impl(...)
{
// try the int overload which will only work,
// if F takes I-1 arguments. Otherwise this
// overload will be selected and we'll try it
// with one element less.
return arity_impl<I - 1, F>(0);
}
template <typename F, size_t MaxArity = 10>
constexpr auto arity_impl()
{
// start checking function signatures with max_arity + 1 elements
constexpr auto tmp = arity_impl<MaxArity + 1, F>(0);
if constexpr(std::is_same_v<std::decay_t<decltype(tmp)>, not_callable_t>) {
return not_callable_t{};
}
else if constexpr (tmp == MaxArity + 1)
{
// if that works, F is considered variadic
return variadic_t{};
}
else
{
// if not, tmp will be the correct arity of F
return tmp;
}
}
}
template <typename F, size_t MaxArity = max_arity>
constexpr auto arity(F&& f) { return detail::arity_impl<std::decay_t<F>, MaxArity>(); }
template <typename F, size_t MaxArity = max_arity>
constexpr auto arity_v = detail::arity_impl<std::decay_t<F>, MaxArity>();
template <typename F, size_t MaxArity = max_arity>
constexpr bool is_variadic_v = std::is_same_v<std::decay_t<decltype(arity_v<F, MaxArity>)>, variadic_t>;
// HERE'S THE IS_FUNCTOR
template<typename T>
constexpr bool is_functor_v = !std::is_same_v<std::decay_t<decltype(arity_v<T>)>, not_callable_t>;
Given the classes in yout question, the following compiles sucessfully (you can even use variadic lambdas:
constexpr auto lambda_func = [](auto...){};
void test_is_functor() {
static_assert(!is_functor_v<int>);
static_assert(!is_functor_v<class0>);
static_assert(is_functor_v<class1>);
static_assert(is_functor_v<class2>);
static_assert(is_functor_v<class3>);
static_assert(is_functor_v<union0>);
static_assert(is_functor_v<final_class>);
static_assert(is_functor_v<decltype(lambda_func)>);
}
See also a running example here.

Container with function member with variable number of arguments

I'm trying to come up with a better way of representing the following:
using InsBase0 = std::tuple<std::string, std::function<void()>>;
static const std::array<InsBase0, 1> ins0_bases = {{
{"NOP", 0x0},
}};
using InsBase1 = std::tuple<std::string, std::function<void(const std::string &)>>;
static const std::array<InsBase1, 7> ins1_bases = {{
{"INC", 0x0},
{"DEC", 0x0},
{"AND", 0x0},
{"OR", 0x0},
{"XOR", 0x0},
{"CP", 0x0},
{"SUB", 0x0},
}};
using InsBase2 = std::tuple<std::string, std::function<void(const std::string &, const std::string&)>>;
static const std::array<InsBase2, 6> ins_bases = {{
{"LD", 0x0},
{"ADD", 0x0},
{"ADC", 0x0},
{"SBC", 0x0},
{"JP", 0x0},
{"JR", 0x0},
}};
(utterly contrived example, imagine functions in place of 0x0 and something more sane like a map instead of an array or a struct instead of the tuple)
The context is that this is an assembler, so I need to map instructions to functions.
In a perfect world, I'd like to be able to put all of the instructions into one array/container (with an additional args member to denote the number of args the function takes), but I'd be happy with not duplicating the definitions with StructName0 as well
Two bits of metaprogramming helpers:
template<std::size_t I>
using index=std::integral_constant<std::size_t, I>;
template<class T> struct tag_t {constexpr tag_t(){};};
template<class T> tag_t<T> tag{};
template<std::size_t, class T>
using indexed_type = T;
Now we define an enum type for each of the argument counts:
enum class zero_op:std::size_t { NOP };
enum class one_op:std::size_t { INC };
enum class two_op:std::size_t { ADD };
Next, a mapping from the types to the argument count:
constexpr index<0> args( tag_t<zero_op> ) { return {}; }
constexpr index<1> args( tag_t<one_op> ) { return {}; }
constexpr index<2> args( tag_t<two_op> ) { return {}; }
This takes a template and a count and a type, and repeatedly passes the type to the template:
template<template<class...>class Z, class T, class Indexes>
struct repeat;
template<template<class...>class Z, class T, std::size_t I>
struct repeat<Z, T, index<I>>:
repeat<Z, T, std::make_index_sequence<I>>
{};
template<template<class...>class Z, class T, std::size_t...Is>
struct repeat<Z, T, std::index_sequence<Is...>> {
using type=Z<indexed_type<Is, T>...>;
};
template<template<class...>class Z, class T, std::size_t N>
using repeat_t = typename repeat<Z, T, index<N>>::type;
We use this to build our std::function signatures:
template<class...Args>
using void_call = std::function<void(Args...)>;
template<std::size_t N, class T>
using nary_operation = repeat_t< void_call, T, N >;
and nary_operation< 3, std::string const& > is std::function<void(std::string const&,std::string const&,std::string const&)>.
We use this to create a compile time polymorphic table:
template<class...Es>
struct table {
template<class E>
using operation = nary_operation<args(tag<E>), std::string const&>;
template<class E>
using subtable = std::map< E, operation<E> >;
std::tuple< subtable<Es>... > tables;
template<class E>
operation<E> const& operator[]( E e ) {
return std::get< subtable<E> >( tables )[e];
}
};
or something like that.
If you have an intance of table<zero_op, one_op, two_op> bob, you can do
bob[ zero_op::NOP ]();
or
bob[ zero_op::INC ]("foo");
or
bob[ zero_op::ADD ]("foo", "bar");
The type of the enum in [] changes the type of the function object returned.
The above probably has typos.
But, the end result is type-safe.
I couldn't figure out a way to store all operations in one structure and still have compile time checks. Yet it is possible to check the number of passed values at runtime.
#include <iostream>
#include <functional>
#include <string>
#include <unordered_map>
class operation
{
using op0_funcptr = void(*)();
using op1_funcptr = void(*)(const std::string&);
using op2_funcptr = void(*)(const std::string&, const std::string&);
using op0_func = std::function<void()>;
using op1_func = std::function<void(const std::string&)>;
using op2_func = std::function<void(const std::string&, const std::string&)>;
std::tuple<
op0_func,
op1_func,
op2_func> m_functions;
public:
operation() :m_functions(op0_func(), op1_func(), op2_func()) {}
operation(const op0_func& op) :m_functions(op, op1_func(), op2_func()) {}
operation(const op0_funcptr& op) :m_functions(op, op1_func(), op2_func()) {}
operation(const op1_func& op) :m_functions(op0_func(), op, op2_func()) {}
operation(const op1_funcptr& op) :m_functions(op0_func(), op, op2_func()) {}
operation(const op2_func& op) :m_functions(op0_func(), op1_func(), op) {}
operation(const op2_funcptr& op) :m_functions(op0_func(), op1_func(), op) {}
operation(const operation& other) = default;
operation(operation&& other) = default;
void operator()() { std::get<op0_func>(m_functions)(); }
void operator()(const std::string& p1) { std::get<op1_func>(m_functions)(p1); }
void operator()(const std::string& p1, const std::string& p2) { std::get<op2_func>(m_functions)(p1, p2); }
};
void nop()
{
std::cout << "NOP" << std::endl;
}
void inc(const std::string& p1)
{
std::cout << "INC(" << p1 << ")" << std::endl;
}
void add(const std::string& p1, const std::string& p2)
{
std::cout << "ADD(" << p1 << ", " << p2 << ")" << std::endl;
}
std::unordered_map<std::string, operation> operations{ {
{ "NOP", nop },
{ "INC", inc },
{ "ADD", add }
} };
int main(int argc, char** argv)
{
operations["NOP"]();
operations["INC"]("R1");
operations["ADD"]("R2", "R3");
operations["ADD"]("R2"); //Throws std::bad_function_call
}
It's by far not the best solution, but it works.
If you want to make the access faster you can also try to change the lower part to something like this:
enum class OP : size_t
{
NOP,
INC,
ADD,
NUM_OPS
};
std::array<operation, (size_t)OP::NUM_OPS> operations{ nop ,inc, add };
int main(int argc, char** argv)
{
operations[(size_t)OP::NOP]();
operations[(size_t)OP::INC]("R1");
operations[(size_t)OP::ADD]("R2", "R3");
//operations[(size_t)OP::ADD]("R2"); //Throws std::bad_function_call
}
I suggest the use of single std::map where the key is the name of the function (NOP, AND, ADD, etc.).
Using inheritance, a trivial base class, a std::function wrapper...
Not really elegant, I suppose, but...
#include <map>
#include <memory>
#include <iostream>
#include <functional>
struct funBase
{
// defined only to permit the dynamic_cast
virtual void unused () const {};
};
template <typename R, typename ... Args>
struct funWrap : public funBase
{
std::function<R(Args...)> f;
funWrap (R(*f0)(Args...)) : f { f0 }
{ }
};
template <typename R, typename ... Args>
std::unique_ptr<funBase> makeUFB (R(*f)(Args...))
{ return std::unique_ptr<funBase>(new funWrap<R, Args...>(f)); }
template <typename F, typename T, bool = std::is_convertible<F, T>::value>
struct getConv;
template <typename F, typename T>
struct getConv<F, T, true>
{ using type = T; };
template <typename F, typename T>
struct getConv<F, T, false>
{ };
template <typename ... Args>
void callF (std::unique_ptr<funBase> const & fb, Args ... args)
{
using derType = funWrap<void,
typename getConv<Args, std::string>::type const & ...>;
derType * pdt { dynamic_cast<derType *>(fb.get()) };
if ( nullptr == pdt )
std::cout << "call(): error in conversion" << std::endl;
else
pdt->f(args...);
}
void fNop ()
{ std::cout << "NOP!" << std::endl; }
void fAnd (std::string const & s)
{ std::cout << "AND! [" << s << ']' << std::endl; }
void fAdd (std::string const & s1, std::string const & s2)
{ std::cout << "ADD! [" << s1 << "] [" << s2 << ']' << std::endl; }
int main()
{
std::map<std::string, std::unique_ptr<funBase>> fm;
fm.emplace("NOP", makeUFB(fNop));
fm.emplace("AND", makeUFB(fAnd));
fm.emplace("ADD", makeUFB(fAdd));
callF(fm["NOP"]); // print NOP!
callF(fm["AND"], "arg"); // print AND! [arg]
callF(fm["ADD"], "arg1", "arg2"); // print ADD! [arg1] [arg2]
callF(fm["ADD"], "arg1"); // print call(): error in conversion
//callF(fm["ADD"], "arg1", 12); // compilation error
return 0;
}
P.s.: works with C++11 too.
Instead of having a std::string argument for your functions, you could use a std::vector<std::string>, so you could store multiple arguments.
That would relate to something like :
using function_t = std::function<void(const std::vector<std::string>&)>;
static const std::unordered_map<std::string, function_t> instructions =
{
{"INC", somefunc},
...
};
And then to call the proper instruction :
std::vector<std::string> arguments = { "zob", "zeb" };
auto result = instructions["INC"](arguments);
Edit :
Here's the rest of how I would do it, to prove you it's not that long :
/**
* Your instruction type. Contains its name,
* the function to call, and the number of args required
*/
struct Instruction {
using function_t = std::function<void(std::vector<std::string>)>;
std::string name;
function_t function;
std::size_t numargs;
Instruction(const std::string& name = "undefined", const function_t& function = function_t(), std::size_t numargs = 0)
: name(name)
, function(function)
, numargs(numargs) {}
}
/**
* Your instruction set. It contains the instructions you want to register in.
* You can call the instructions safely through this
*/
struct InstructionSet {
std::unordered_map<std::string, Instruction> instructions;
void callInstruction(const std::string& inst_name, const std::vector<std::string>& arguments) {
if (!instructions.count(inst_name))
return; // no instruction named "inst_name", return or throw something relevant
auto instruction = instructions[inst_name];
if (instruction.numargs != arguments.size())
return; // too many / not enough parameters, return or throw something relevant
instruction.function(arguments);
}
void registerInstruction(const Instruction& instruction) {
instructions[instruction.name] = instruction;
}
};
int main() {
InstructionSet instruction_set;
instruction_set.registerInstruction(Instruction(
"INC",
[](const std::vector<std::string>& arguments) {
bake_cookies_plz(arguments);
},
2)
);
instruction_set.callInstruction("INC", { "1", "2" });
return 0;
}
Note 1 : in this example, the InstructionSet is responsible for checking the number of arguments passed, but the functions could do it themselves. I would do that if there was a possibility of variable arguments count
Note 2 : the registering part is not quite elegant with lambdas, but it's quick to write
Note 3 : if you want more type safety for your arguments, go check max66 answer to get an idea of how to master templates in this situation

Switch statement variadic template expansion

Let me please consider the following synthetic example:
inline int fun2(int x) {
return x;
}
inline int fun2(double x) {
return 0;
}
inline int fun2(float x) {
return -1;
}
int fun(const std::tuple<int,double,float>& t, std::size_t i) {
switch(i) {
case 0: return fun2(std::get<0>(t));
case 1: return fun2(std::get<1>(t));
case 2: return fun2(std::get<2>(t));
}
}
The question is how should I expand this to the general case
template<class... Args> int fun(const std::tuple<Args...>& t, std::size_t i) {
// ?
}
Guaranteeing that
fun2 can be inlined into fun
search complexity not worse than O(log(i)) (for large i).
It is known that optimizer usually uses lookup jump table or compile-time binary search tree when large enough switch expanded. So, I would like to keep this property affecting performance for large number of items.
Update #3: I remeasured performance with uniform random index value:
1 10 20 100
#TartanLlama
gcc ~0 42.9235 44.7900 46.5233
clang 10.2046 38.7656 40.4316 41.7557
#chris-beck
gcc ~0 37.564 51.3653 81.552
clang ~0 38.0361 51.6968 83.7704
naive tail recursion
gcc 3.0798 40.6061 48.6744 118.171
clang 11.5907 40.6197 42.8172 137.066
manual switch statement
gcc 41.7236
clang 7.3768
Update #2: It seems that clang is able to inline functions in #TartanLlama solution whereas gcc always generates function call.
Ok, I rewrote my answer. This gives a different approach to what TartanLlama and also what I suggested before. This meets your complexity requirement and doesn't use function pointers so everything is inlineable.
Edit: Much thanks to Yakk for pointing out a quite significant optimization (for the compile-time template recursion depth required) in comments
Basically I make a binary tree of the types / function handlers using templates, and implement the binary search manually.
It might be possible to do this more cleanly using either mpl or boost::fusion, but this implementation is self-contained anyways.
It definitely meets your requirements, that the functions are inlineable and runtime look up is O(log n) in the number of types in the tuple.
Here's the complete listing:
#include <cassert>
#include <cstdint>
#include <tuple>
#include <iostream>
using std::size_t;
// Basic typelist object
template<typename... TL>
struct TypeList{
static const int size = sizeof...(TL);
};
// Metafunction Concat: Concatenate two typelists
template<typename L, typename R>
struct Concat;
template<typename... TL, typename... TR>
struct Concat <TypeList<TL...>, TypeList<TR...>> {
typedef TypeList<TL..., TR...> type;
};
template<typename L, typename R>
using Concat_t = typename Concat<L,R>::type;
// Metafunction First: Get first type from a typelist
template<typename T>
struct First;
template<typename T, typename... TL>
struct First <TypeList<T, TL...>> {
typedef T type;
};
template<typename T>
using First_t = typename First<T>::type;
// Metafunction Split: Split a typelist at a particular index
template<int i, typename TL>
struct Split;
template<int k, typename... TL>
struct Split<k, TypeList<TL...>> {
private:
typedef Split<k/2, TypeList<TL...>> FirstSplit;
typedef Split<k-k/2, typename FirstSplit::R> SecondSplit;
public:
typedef Concat_t<typename FirstSplit::L, typename SecondSplit::L> L;
typedef typename SecondSplit::R R;
};
template<typename T, typename... TL>
struct Split<0, TypeList<T, TL...>> {
typedef TypeList<> L;
typedef TypeList<T, TL...> R;
};
template<typename T, typename... TL>
struct Split<1, TypeList<T, TL...>> {
typedef TypeList<T> L;
typedef TypeList<TL...> R;
};
template<int k>
struct Split<k, TypeList<>> {
typedef TypeList<> L;
typedef TypeList<> R;
};
// Metafunction Subdivide: Split a typelist into two roughly equal typelists
template<typename TL>
struct Subdivide : Split<TL::size / 2, TL> {};
// Metafunction MakeTree: Make a tree from a typelist
template<typename T>
struct MakeTree;
/*
template<>
struct MakeTree<TypeList<>> {
typedef TypeList<> L;
typedef TypeList<> R;
static const int size = 0;
};*/
template<typename T>
struct MakeTree<TypeList<T>> {
typedef TypeList<> L;
typedef TypeList<T> R;
static const int size = R::size;
};
template<typename T1, typename T2, typename... TL>
struct MakeTree<TypeList<T1, T2, TL...>> {
private:
typedef TypeList<T1, T2, TL...> MyList;
typedef Subdivide<MyList> MySubdivide;
public:
typedef MakeTree<typename MySubdivide::L> L;
typedef MakeTree<typename MySubdivide::R> R;
static const int size = L::size + R::size;
};
// Typehandler: What our lists will be made of
template<typename T>
struct type_handler_helper {
typedef int result_type;
typedef T input_type;
typedef result_type (*func_ptr_type)(const input_type &);
};
template<typename T, typename type_handler_helper<T>::func_ptr_type me>
struct type_handler {
typedef type_handler_helper<T> base;
typedef typename base::func_ptr_type func_ptr_type;
typedef typename base::result_type result_type;
typedef typename base::input_type input_type;
static constexpr func_ptr_type my_func = me;
static result_type apply(const input_type & t) {
return me(t);
}
};
// Binary search implementation
template <typename T, bool b = (T::L::size != 0)>
struct apply_helper;
template <typename T>
struct apply_helper<T, false> {
template<typename V>
static int apply(const V & v, size_t index) {
assert(index == 0);
return First_t<typename T::R>::apply(v);
}
};
template <typename T>
struct apply_helper<T, true> {
template<typename V>
static int apply(const V & v, size_t index) {
if( index >= T::L::size ) {
return apply_helper<typename T::R>::apply(v, index - T::L::size);
} else {
return apply_helper<typename T::L>::apply(v, index);
}
}
};
// Original functions
inline int fun2(int x) {
return x;
}
inline int fun2(double x) {
return 0;
}
inline int fun2(float x) {
return -1;
}
// Adapted functions
typedef std::tuple<int, double, float> tup;
inline int g0(const tup & t) { return fun2(std::get<0>(t)); }
inline int g1(const tup & t) { return fun2(std::get<1>(t)); }
inline int g2(const tup & t) { return fun2(std::get<2>(t)); }
// Registry
typedef TypeList<
type_handler<tup, &g0>,
type_handler<tup, &g1>,
type_handler<tup, &g2>
> registry;
typedef MakeTree<registry> jump_table;
int apply(const tup & t, size_t index) {
return apply_helper<jump_table>::apply(t, index);
}
// Demo
int main() {
{
tup t{5, 1.5, 15.5f};
std::cout << apply(t, 0) << std::endl;
std::cout << apply(t, 1) << std::endl;
std::cout << apply(t, 2) << std::endl;
}
{
tup t{10, 1.5, 15.5f};
std::cout << apply(t, 0) << std::endl;
std::cout << apply(t, 1) << std::endl;
std::cout << apply(t, 2) << std::endl;
}
{
tup t{15, 1.5, 15.5f};
std::cout << apply(t, 0) << std::endl;
std::cout << apply(t, 1) << std::endl;
std::cout << apply(t, 2) << std::endl;
}
{
tup t{20, 1.5, 15.5f};
std::cout << apply(t, 0) << std::endl;
std::cout << apply(t, 1) << std::endl;
std::cout << apply(t, 2) << std::endl;
}
}
Live on Coliru:
http://coliru.stacked-crooked.com/a/3cfbd4d9ebd3bb3a
If you make fun2 into a class with overloaded operator():
struct fun2 {
inline int operator()(int x) {
return x;
}
inline int operator()(double x) {
return 0;
}
inline int operator()(float x) {
return -1;
}
};
then we can modify dyp's answer from here to work for us.
Note that this would look a lot neater in C++14, as we could have all the return types deduced and use std::index_sequence.
//call the function with the tuple element at the given index
template<class Ret, int N, class T, class Func>
auto apply_one(T&& p, Func func) -> Ret
{
return func( std::get<N>(std::forward<T>(p)) );
}
//call with runtime index
template<class Ret, class T, class Func, int... Is>
auto apply(T&& p, int index, Func func, seq<Is...>) -> Ret
{
using FT = Ret(T&&, Func);
//build up a constexpr array of function pointers to index
static constexpr FT* arr[] = { &apply_one<Ret, Is, T&&, Func>... };
//call the function pointer at the specified index
return arr[index](std::forward<T>(p), func);
}
//tag dispatcher
template<class Ret, class T, class Func>
auto apply(T&& p, int index, Func func) -> Ret
{
return apply<Ret>(std::forward<T>(p), index, func,
gen_seq<std::tuple_size<typename std::decay<T>::type>::value>{});
}
We then call apply and pass the return type as a template argument (you could deduce this using decltype or C++14):
auto t = std::make_tuple(1,1.0,1.0f);
std::cout << apply<int>(t, 0, fun2{}) << std::endl;
std::cout << apply<int>(t, 1, fun2{}) << std::endl;
std::cout << apply<int>(t, 2, fun2{}) << std::endl;
Live Demo
I'm not sure if this will completely fulfil your requirements due to the use of function pointers, but compilers can optimize this kind of thing pretty aggressively. The searching will be O(1) as the pointer array is just built once then indexed directly, which is pretty good. I'd try this out, measure, and see if it'll work for you.

Change boolean flags into template arguments

Suppose I have a versatile function with about four boolean flags:
int do_something(int arg, bool flag1, bool flag2, bool flag3, bool flag4) {
for(int i = 0; i < 1000000; i++) {
if(flag1)
// Do something 1
if(flag2)
// Do something 2
if(flag3)
// Do something 3
if(flag4)
// Do something 4
//Do something else 5
}
}
But I don't want to incur any costs for branching on these flags in the inner loop so I change them to templates (allowing the compiler to optimize away the conditionals):
template<bool flag1, bool flag2, bool flag3, bool flag4>
int do_something_helper(int arg) {
for(int i = 0; i < 1000000; i++) {
if(flag1)
// Do something 1
if(flag2)
// Do something 2
if(flag3)
// Do something 3
if(flag4)
// Do something 4
//Do something else 5
}
}
How can I write the do_something method now? The only way I know is as follows:
int do_something(int arg, bool flag1, bool flag2, bool flag3, bool flag4) {
if(flag1) {
if(flag2) {
if(flag3) {
if(flag4) {
return do_something_helper<true,true,true,true>(arg);
}else{
return do_something_helper<true,true,true,false>(arg);
}
}else{
if(flag4) {
return do_something_helper<true,true,false,true>(arg);
}else{
return do_something_helper<true,true,false,false>(arg);
}
}
//... You get the picture
}
Is there some way to get the compiler to write the above code automatically so I don't have to include this ugly monstrosity in my beautiful code-base?
What I would do is take a functor and a pack of arguments and an argument index and a range. Then I would replace the indexed argument with std::integral_constant<type, value> and call the functor. The bool case is easiest, as the range is obvious, so I would write that one first.
Then you can chain such replaces and functors to replace each one of the bools with compile time types. I would use the same functor for them all, with N overloads, esch replacing one bool with std::integral_constant<bool, X> where X is a template parameter.
The last one would then call the final method, with integral_constant instead of bool.
Note that this expands to an exponential amount of instantiations, so be careful.
The argument manipulation code would be fun to write.
Here is a live example.
Amusingly, the boilerplate to do the above is probably still bulkier, but hopefully less typo-prone and easier to test.
#include <iostream>
#include <tuple>
template<unsigned...Is> struct indexes {typedef indexes<Is...> type;};
template<unsigned min, unsigned max, unsigned...Is> struct make_indexes: make_indexes<min, max-1, max-1, Is...> {};
template<unsigned min, unsigned...Is> struct make_indexes<min, min, Is...>: indexes<Is...> {};
template<unsigned max, unsigned min=0>
using Indexes = typename make_indexes<min, max>::type;
template<unsigned index, typename Functor, typename... Args, unsigned... Before, unsigned... After>
void map_bool_to_compile_time_helper( indexes<Before...>, indexes<After...>, Functor&& f, std::tuple<Args...> args )
{
if (std::get<index>( args )) {
std::forward<Functor>(f)( std::get<Before>(args)..., std::true_type(), std::get<After>(args)... );
} else {
std::forward<Functor>(f)( std::get<Before>(args)..., std::false_type(), std::get<After>(args)... );
}
}
template<unsigned index, typename Functor, typename... Args>
void map_bool_to_compile_time( Functor&& f, Args&&... args )
{
map_bool_to_compile_time_helper<index>( Indexes<index>(), Indexes<sizeof...(Args), index+1>(), std::forward<Functor>(f), std::make_tuple<Args&&...>(std::forward<Args>(args)...) );
}
template<typename Functor, unsigned... indexes>
struct map_bools_to_compile_time_helper;
template<typename Functor, unsigned index, unsigned... indexes>
struct map_bools_to_compile_time_helper<Functor, index, indexes...> {
Functor&& f;
map_bools_to_compile_time_helper(Functor&& in):f(std::forward<Functor>(in)) {}
template< typename... Args>
void operator()( Args&&... args) const {
map_bool_to_compile_time<index>( map_bools_to_compile_time_helper<Functor, indexes...>{std::forward<Functor>(f)}, std::forward<Args>(args)... );
}
};
template<typename Functor>
struct map_bools_to_compile_time_helper<Functor> {
Functor&& f;
map_bools_to_compile_time_helper(Functor&& in):f(std::forward<Functor>(in)) {}
template<typename... Args>
void operator()( Args&&... args) const {
std::forward<Functor>(f)(std::forward<Args>(args)...);
}
};
template<unsigned... Is, typename Functor, typename... Args>
void map_bools_to_compile_time( indexes<Is...>, Functor&& f, Args&&... args ) {
map_bools_to_compile_time_helper<Functor, Is...>{ std::forward<Functor>(f) }( std::forward<Args>(args)... );
}
struct test {
template<bool b>
void operator()( int x, std::integral_constant< bool, b > ) { std::cout << x << ": " << b <<"!\n"; }
};
struct test2 {
template<bool b0, bool b1, bool b2>
void operator()( int x, std::integral_constant< bool, b0 >, std::integral_constant< bool, b1 >, std::integral_constant< bool, b2 > )
{
std::cout << x << ": " << b0 << b1 << b2 << "\n";
}
};
int main() {
map_bools_to_compile_time( indexes<1>(), test(), 1, true );
map_bool_to_compile_time<1>( test(), 2, false );
map_bools_to_compile_time( indexes<1,2,3>(), test2(), 3, true, false, true );
}
Updated with support for any number of arguments at any number of indexes.
You can use templates to organize static dispatch - which will allow to replace branching statement with function overload. This is a rather simple idea, here is a small example:
template <int Val>
struct Int2Type
{
static const int val_= Val;
};
int do_something(int arg, Int2Type<1>)
{
// do smth when flag == 1
}
int do_something(int arg, Int2Type<2>)
{
// do smth when flag == 2
}
... the same principle is applied (by the value of a flag needed overloaded function is called)

Type sensitive tuple visitor

Suppose I have a std::tuple made up of types like
struct A {
static void tip();
};
struct B {
static void tip();
};
struct Z {
};
std::tuple<const A&,const B&,const Z&> tpl;
Yes, I need separate A, B. (The implementation of ::tip() differs for each type.) What I try to implement is a type-sensitive "visitor" that iterates through the tuple starting from the beginning to the end. Upon visiting a particular element of type T a function should be called depending on whether T has the ::tip() method or not. In the simple example of above only A and B have ::tip() implemented and Z not. So, the iterator should call twice the function for types with the ::tip() method and once the other function.
Here is what I came up with:
template< int N , bool end >
struct TupleIter
{
template< typename T , typename... Ts >
typename std::enable_if< std::is_function< typename T::tip >::value , void >::type
static Iter( const T& dummy , const std::tuple<Ts...>& tpl ) {
std::cout << "tip\n";
std::get<N>(tpl); // do the work
TupleIter<N+1,sizeof...(Ts) == N+1>::Iter( std::get<N+1>(tpl) , tpl );
}
template< typename T , typename... Ts >
typename std::enable_if< ! std::is_function< typename T::tip >::value , void >::type
static Iter( const T& dummy , const std::tuple<Ts...>& tpl ) {
std::cout << "no tip\n";
std::get<N>(tpl); // do the work
TupleIter<N+1,sizeof...(Ts) == N+1>::Iter( std::get<N+1>(tpl) , tpl );
}
};
template< int N >
struct TupleIter<N,true>
{
template< typename T , typename... Ts >
static void Iter( const std::tuple<Ts...>& tpl ) {
std::cout << "end\n";
}
};
I use a dummy instance of the type of the element at the iterator position and decide via enable_if which function to call. Unfortunately this doesn't work/isn't a nice solution:
The compiler complains about recursive instantiation
The const T& dummy is not a clean solution
I was wondering if enable_if is the right strategy to do the decision and how can one recursively iterate through the std::tuple capturing the first type and keeping all the remaining arguments in vital state. Read through How to split a tuple? but it doesn't do any decision.
How can one implement such a thing in a correct and portable way in C++11?
Well, it was harder than I expected, but this works.
Some things you were doing wrong/that I modified:
You can't evaluate this: std::is_function< typename T::tip >::value, since T::tip is not a type. Even if this could be evaluated, what would happen when T::tip does not exist? Substitution would still fail.
Since you use const references as your tuple's inner types, you had to clean them before trying to find the tip member inside them. By cleaning I mean removing const and removing the reference.
That dummy type stuff was not a good idea, there was no need to use that parameter. You can achieve the same thing using std::tuple_element, which retrieves the i-th type from a tuple.
I modified TupleIter's template parameters to the following, which means:
"TupleIter that processes the index-th type, inside a tuple of size n".
template<size_t index, size_t n>
struct TupleIter;
The whole code is this:
#include <tuple>
#include <iostream>
#include <type_traits>
struct A {
static void tip();
};
struct B {
static void tip();
};
struct Z {
};
// Indicates whether the template parameter contains a static member named tip.
template<class T>
struct has_tip {
template<class U>
static char test(decltype(&U::tip));
template<class U>
static float test(...);
static const bool value = sizeof(test<typename std::decay<T>::type>(0)) == sizeof(char);
};
// Indicates whether the n-th type contains a tip static member
template<size_t n, typename... Ts>
struct nth_type_has_tip {
static const bool value = has_tip<typename std::tuple_element<n, std::tuple<Ts...>>::type>::value;
};
// Generic iteration
template<size_t index, size_t n>
struct TupleIter
{
template< typename... Ts >
typename std::enable_if< nth_type_has_tip<index, Ts...>::value , void >::type
static Iter(const std::tuple<Ts...>& tpl)
{
std::cout << "tip\n";
TupleIter<index + 1, n>::Iter(tpl );
}
template< typename... Ts >
typename std::enable_if< !nth_type_has_tip<index, Ts...>::value , void >::type
static Iter(const std::tuple<Ts...>& tpl) {
std::cout << "no tip\n";
TupleIter<index + 1, n>::Iter(tpl );
}
};
// Base class, we've reached the tuple end
template<size_t n>
struct TupleIter<n, n>
{
template<typename... Ts >
static void Iter( const std::tuple<Ts...>& tpl ) {
std::cout << "end\n";
}
};
// Helper function that forwards the first call to TupleIter<>::Iter
template<typename... Ts>
void iterate(const std::tuple<Ts...> &tup) {
TupleIter<0, sizeof...(Ts)>::Iter(tup);
}
int main() {
A a;
B b;
Z z;
std::tuple<const A&,const B&,const Z&> tup(a,b,z);
iterate(tup);
}
Here is another take on the question, very similar to mfontanini answer, but showcasing:
boost::fusion::for_each (instead of manually iterate over the tuple).
A variant for implementing has_type using an expression-based SFINAE approach, that I feel a little bit simpler to follow than the usual sizeof trick.
#include <boost/tuple/tuple.hpp>
#include <boost/fusion/include/boost_tuple.hpp>
#include <boost/fusion/algorithm.hpp>
#include <iostream>
struct nat // not a type
{
private:
nat();
nat(const nat&);
nat& operator=(const nat&);
~nat();
};
template <typename T>
struct has_tip
{
static auto has_tip_imp(...) -> nat;
template <typename U>
static auto has_tip_imp(U&&) -> decltype(U::tip());
typedef decltype(has_tip_imp(std::declval<T>())) type;
static const bool value = !std::is_same<type, nat>::value;
};
struct CallTip
{
template<typename T>
typename std::enable_if<has_tip<T>::value>::type
operator()(T& t) const
{
std::cout << "tip\n";
T::tip();
}
template<typename T>
typename std::enable_if<!has_tip<T>::value>::type
operator()(T& t) const
{
std::cout << "no tip\n";
return;
}
};
struct A {
static void tip(){}
};
struct B {
static void tip(){}
};
struct Z {
};
int main()
{
A a;
B b;
Z z;
boost::tuple<const A&,const B&,const Z&> tpl(a, b, z);
boost::fusion::for_each(tpl, CallTip());
}
Note that if your compiler support variadic template you can use std::tuple instead of boost::tuple inside fusion::for_each by including #include<boost/fusion/adapted/std_tuple.hpp>
Edit :
As pointed by Xeo in the comment, it is possible to simplify a lot the expression-SFINAE approach by removing completely the trait has_tip and simply forward to a little call helper.
The final code is really neat and tight !
#include <boost/tuple/tuple.hpp>
#include <boost/fusion/include/boost_tuple.hpp>
#include <boost/fusion/algorithm.hpp>
#include <iostream>
struct CallTip
{
template<typename T>
void operator()(const T& t) const
{
call(t);
}
template<class T>
static auto call(const T&) -> decltype(T::tip())
{
std::cout << "tip\n";
T::tip();
}
static void call(...)
{
std::cout << "no tip\n";
}
};
struct A {
static void tip(){}
};
struct B {
static void tip(){}
};
struct Z {
};
int main()
{
A a;
B b;
Z z;
boost::tuple<const A&,const B&,const Z&> tpl(a, b, z);
boost::fusion::for_each(tpl, CallTip());
}