For sorting user defined typed objects in a flexible way (i.e. by naming a member variable) I wrote a template to generate lambdas to do the comparison. Additionally to chain comparisons of different member variables in case of equality I wrote a second template. It works so far but I want bpth templates to be completely independent from any concrete types. Therefore I have to get a class type from a class member pointer type.
This is my user defined example type:
struct Person { string name; int age, height; };
To sort objects of it by looking at e.g. the age I want to write it like:
auto result = max_element(persons.begin(), persons.end(), order_by(&Person::age));
This works with the template:
template<class F> //F is Person::* e.g. &Person::age
auto order_by(F f) {
return [f](const Person& smaller, const Person& bigger) {
return smaller.*f < bigger.*f;
};
}
To be able to chain multiple comparisons in case of equal values like this:
result = max_element(persons.begin(), persons.end(), order_by(&Person::age) | order_by(&Person::height));
I wrote the template:
//compose two orderings :
template<class F1, class F2>
auto operator|(F1 f1, F2 f2) {
return [f1, f2](auto a, auto b) {
auto res = f1(a, b);
auto inv_res = f1(b, a);
if (res != inv_res)
return res;
return f2(a, b);
};
}
Here the first comparison is done and if it detects that a==b (a is not smaller than b and b is not smaller than a) it uses the second comparison function.
What I want to achieve is to be independent of the Person type in the first template. How could this be solved?
You can easily extract the class and type of the pointer-to-member in your first template with some small modifications.
template<class Class, class Type>
auto order_by(Type Class::* f) {
return [f](const Class& smaller, const Class& bigger) {
return smaller.*f < bigger.*f;
};
}
I would forward job to std::tuple with something like:
template <typename... Projs>
auto order_by(Projs... projs) {
return [=](const auto& lhs, const auto& rhs) {
return std::forward_as_tuple(std::invoke(projs, lhs)...)
< std::forward_as_tuple(std::invoke(projs, rhs)...);
};
}
with usage
result = std::max_element(persons.begin(), persons.end(), order_by(&Person::age, &Person::height));
ranges algorithms (C++20 or range-v3) separate comparison from projection, so you might have (by changing order_by to project_to):
result = ranges::max_element(persons, std::less<>{}, project_to(&Person::age, &Person::height));
You can get the class type from the type of a pointer to member like this:
#include <type_traits>
#include <iostream>
struct Foo {
int bar;
};
template <typename T>
struct type_from_member;
template <typename M,typename T>
struct type_from_member< M T::* > {
using type = T;
};
int main()
{
std::cout << std::is_same< type_from_member<decltype(&Foo::bar)>::type, Foo>::value;
}
Output:
1
Because type_from_member< decltype(&Foo::bar)>::type is Foo.
So you could use it like this:
template<class F> //F is Person::* e.g. &Person::age
auto order_by(F f) {
using T = typename type_from_member<F>::type;
return [f](const T& smaller, const T& bigger) {
return smaller.*f < bigger.*f;
};
}
I want to define a class, called Nested here, that will contains two or more (one here) data members that support arithmetic operations using expression templates, for example an std::valarray. For this class itself, I am defining its own expression templates and I want to "forward" the arithmetic operations down to the members.
A minimal (non)working example is given below:
#include <iostream>
#include <valarray>
template <typename E>
struct NestedExpr {
operator const E& () const {
return *static_cast<const E*>(this);
}
};
template <typename A>
class Nested : public NestedExpr <Nested<A>>{
private:
A a;
public:
Nested(const A& _a) : a(_a) {}
template <typename E>
inline Nested<A>& operator = (const NestedExpr<E>& _expr) {
const E& expr(_expr);
a = expr.get_a();
return *this;
}
inline A& get_a() { return a; }
inline const A& get_a() const { return a; }
};
// ================================================================= //
template <typename ARG, typename S>
class NestedMul : public NestedExpr<NestedMul<ARG, S>> {
public:
const ARG& arg;
const S s;
NestedMul(const ARG& _arg, S _s) : arg(_arg), s(_s) {}
inline auto get_a() const { return arg.get_a() * s; };
};
template< typename ARG, typename S>
inline NestedMul<ARG, S> operator * (S s, const NestedExpr<ARG>& arg) {
return {arg, s};
}
// ================================================================= //
template <typename ARG1, typename ARG2>
class NestedAdd : public NestedExpr<NestedAdd<ARG1, ARG2>> {
public:
const ARG1& arg1;
const ARG2& arg2;
NestedAdd(const ARG1& _arg1, const ARG2& _arg2)
: arg1(_arg1), arg2(_arg2) {}
inline auto get_a() const { return arg1.get_a() + arg2.get_a(); };
};
template<typename ARG1, typename ARG2>
inline NestedAdd<ARG1, ARG2>
operator + (const NestedExpr<ARG1>& arg1, const NestedExpr<ARG2>& arg2) {
return {arg1, arg2};
}
int main () {
std::valarray<double> x1 = {4.0};
std::valarray<double> x2 = {3.0};
std::valarray<double> x3 = {0.0};
std::valarray<double> x4 = {0.0};
auto a = Nested<std::valarray<double>>(x1);
auto b = Nested<std::valarray<double>>(x2);
auto c = Nested<std::valarray<double>>(x3);
// this returns 21
c = 2*a + 3*b;
std::cout << c.get_a()[0] << std::endl;
// works as expected, returns 17
x4 = 2*x1 + 3*x2;
std::cout << x4[0] << std::endl;
}
The output of this program is
21
17
i.e. forwarding the expression down to the member does not seem to provide the expected result obtained directly from using the valarrays.
Any help here is appreciated.
In the below function definition:
inline auto get_a() const { return arg.get_a() * s; };
your expected behavior is that auto deduces std::valarray<double>, that is, the result type of a multiplication of std::valarray<double> and int which is a new object that already stores values multiplied by the integer.
This is how operator* is defined [valarray.binary]/p2:
template <class T>
valarray<T> operator*(const valarray<T>&,
const typename valarray<T>::value_type&);
However, there's the following paragraph in the standard [valarray.syn]/p3:
Any function returning a valarray<T> is permitted to return an object of another type, provided all the const member functions of valarray<T> are also applicable to this type. This return type shall not add more than two levels of template nesting over the most deeply nested argument type.
This type must be convertible to std::valarray<double>, but itself, for optimization purposes, may not represent the actual result before that conversion happens.
That is, here's the actual type deduced for auto by GCC:
std::_Expr<std::__detail::_BinClos<std::__multiplies
, std::_ValArray
, std::_Constant, double, double>, double>
and here's what Clang uses:
std::__1::__val_expr<std::__1::_BinaryOp<std::__1::multiplies<double>,
std::__1::valarray<double>, std::__1::__scalar_expr<double> > >
In other words, you are returning by value an object which probably defers the actual computations. In order to do so, those intermediate objects need to store somehow the deferred subexpressions.
Inspecting GCC libstdc++'s implementation, one can find the following representation:
template <class _Oper, class _FirstArg, class _SecondArg>
class _BinBase
{
public:
typedef typename _FirstArg::value_type _Vt;
typedef typename __fun<_Oper, _Vt>::result_type value_type;
_BinBase(const _FirstArg& __e1, const _SecondArg& __e2)
: _M_expr1(__e1), _M_expr2(__e2) {}
// [...]
private:
const _FirstArg& _M_expr1;
const _SecondArg& _M_expr2;
};
Note that subexpressions are stored as references. This means that in the definition of get_a():
return arg1.get_a() + arg2.get_a();
_M_expr1 and _M_expr2 are bound to temporary objects:
arg1.get_a()
arg2.get_a()
i.e., intermediate objects which are the results of multiplications, whose lifetime ends as soon as NextedAdd::get_a() exits, leading to undefined behavior when the result is eventually computed, in particular, when the implementation attempts to access each individual element of that intermediate subexpressions:
value_type operator[](size_t __i) const
{
return _Oper()(_M_expr1[__i], _M_expr2[__i]);
}
A quick solution would be to use the following return type:
std::decay_t<decltype(arg.get_a())> get_a() const { return arg.get_a() * s; }
This will recursively ensure that the final result type of any operation will be whatever the original type T in Nested<T> was, i.e., std::valarray<double>.
DEMO
I am trying to build a constructor to take an array as an argument which overloads another who take a scalar instead. Code is below.
#include <iostream>
template <typename T>
class SmallVec { // This is a 3 dimensional vector class template
public:
T data[3] = {0}; // internal data of class
template <typename U>
explicit SmallVec(const U& scalar) { // if a scalar, copy it to each element in data
for(auto &item : data) {
item = static_cast<T>(scalar);
}
}
template <typename U>
explicit SmallVec(const U* vec) { // if a vector, copy one by one
for(auto &item : data) {
item = static_cast<T>(*vec);
vec++;
}
}
};
int main() {
float num = 1.2;
float *arr = new float[3];
arr[2] = 3.4;
SmallVec<float> vec1(num); // take num, which works fine
SmallVec<float> vec2(arr); // !!!--- error happens this line ---!!!
std::cout << vec1.data[2] << " " << vec2.data[2] << std::endl;
return 0;
}
The compiler complains that
error: invalid static_cast from type 'float* const' to type 'float'
Obviously, vec2(arr) still calls the first constructor. However, if I remove template <typename U> and replace U to T. The program just works fine. What should I do to correct this?
Any suggestions are appreciated!
Here's how to use SFINAE to get what you want:
#include <vector>
#include <map>
#include <string>
using namespace std;
template<class T>
struct Foo {
template <class U, typename enable_if<is_pointer<U>::value, int>::type = 0>
Foo(U u){}
template <class U, typename enable_if<!is_pointer<U>::value, int>::type = 0>
Foo(U u){}
};
int main()
{
Foo<int> f('a'); // calls second constructor
Foo<int> f2("a"); // calls first constructor
}
live: https://godbolt.org/g/ZPcb5T
I am trying to build a constructor to take an array as an argument
(...)
explicit SmallVec(const U* vec) { // if a vector, copy one by one
You do not take an array. You take a pointer, which may or may not point to an array, and even if it points to an array, who says that the array has at least three elements? That's a serious design flaw.
C++ does allow you to take raw arrays by reference or const reference, even though the syntax is horrible:
explicit SmallVec(const U (&vec)[3]) {
The implementation of the constructor is then also different:
for(int index = 0; index < 3; ++index) {
data[index] = static_cast<T>(vec[index]);
}
Looking at main, however, the problem goes deeper. You use new[] to allocate an array dynamically. That's already a very bad idea. Coincidentally, your example also misses a delete[]. Why don't you use a local array instead?
float arr[3];
This will make your program compile and probably run correctly, but there's still undefined behaviour in your code, because you only set the 3rd element of the array to a valid value; the other two elements remain uninitialised, and reading from an uninitialised float, even if you just copy it, formally results in undefined behaviour.
So better make it:
float arr[3] = { 0.0, 0.0, 3.4 };
In addition to that, C++11 invites you to use std::array, which generally makes things a bit safer and improves the syntax. Here is a complete example:
#include <iostream>
#include <array>
template <typename T>
class SmallVec { // This is a 3 dimensional vector class template
public:
std::array<T, 3> data; // internal data of class
template <typename U>
explicit SmallVec(const U& scalar) { // if a scalar, copy it to each element in data
for(auto &item : data) {
item = static_cast<T>(scalar);
}
}
template <typename U>
explicit SmallVec(std::array<U, 3> const& vec) { // if a vector, copy one by one
for(int index = 0; index < 3; ++index) {
data[index] = static_cast<T>(vec[index]);
}
}
};
int main() {
float num = 1.2;
std::array<float, 3> arr = { 0.0, 0.0, 3.4 };
SmallVec<float> vec1(num);
SmallVec<float> vec2(arr);
std::cout << vec1.data[2] << " " << vec2.data[2] << std::endl;
return 0;
}
Even though both constructors use the explicit specifier and try to avoid type conversions you should note that the first is just as good a candidate as the second. If you substitute U for float* you will get:
explicit SmallVec(const float*& scalar)
which is totally acceptable and will explain the compilation error.
You could resolve the problem by changing the second constructor to:
template <typename U>
explicit SmallVec(U* const vec) { // if a vector, copy one by one
U* local = vec;
for(auto &item : data) {
item = static_cast<T>(*local);
local++;
}
}
However, I suggest an even more explicit way:
class ScalarCopy {};
class VectorCopy {};
...
template <typename U>
SmallVec(const U& vec, ScalarCopy);
template <typename U>
SmallVec(const U* const vec, VectorCopy);
and make explicit calls:
SmallVec<float> vec1(num, ScalarCopy());
SmallVec<float> vec2(arr, VectorCopy());
Here is code that I hope explains what I want to achieve.
vector<int> ints;
vector<double> doubles;
struct Arg {
enum Type {
Int,
Double
};
Type type;
int index;
};
template <typename F>
void Call(const F& f, const vector<Arg>& args) {
// TODO:
// - First assert that count and types or arguments of <f> agree with <args>.
// - Call "f(args)"
}
// Example:
void copy(int a, double& b) {
b = a;
}
int test() {
Call(copy, {{Int, 3}, {Double, 2}}); // copy(ints[3], double[2]);
}
Can this be done in C++11 ?
If yes, can the solution be simplified in C++14 ?
I'd do this in two steps.
First, I'd wrap f in an object able to understand Arg-like parameters, and generate errors on failure. For simplicity, suppose we throw.
This is a bit simpler than your Arg to be understood at this layer, so I might translate Arg into MyArg:
struct MyArg {
MyArg(MyArg const&)=default;
MyArg(int* p):i(p){}
MyArg(double* p):d(p){}
MyArg(Arg a):MyArg(
(a.type==Arg::Int)?
MyArg(&ints.at(a.index)):
MyArg(&doubles.at(a.index))
) {}
int * i = nullptr;
double* d = nullptr;
operator int&(){ if (!i) throw std::invalid_argument(""); return *i; }
operator double&(){ if (!d) throw std::invalid_argument(""); return *d; }
};
We map void(*)(Ts...) to std::function<void(MyArg, MyArg, MyArg)> like this:
template<class T0, class T1>using second_type = T1;
template<class...Ts>
std::function<void( second_type<Ts,MyArg>... )> // auto in C++14
my_wrap( void(*f)(Ts...) ) {
return [f](second_type<Ts,MyArg>...args){
f(args...);
};
}
now all that is left is counting function parameter count vs vector size count, and unpacking the std::vector into a function call.
The last looks like:
template<class...Ts, size_t...Is>
void call( std::function<void(Ts...)> f, std::index_sequence<Is...>, std::vector<Arg> const& v ) {
f( v[Is]... );
}
template<class...Ts>
void call( std::function<void(Ts...)> f, std::vector<Arg> const& v ) {
call( std::move(f), std::index_sequence_for<Ts...>{}, v );
}
where index_sequence and index_sequence_for are C++14, but equivalents can be implemented in C++11 (there are many implementations on stack overflow).
So we end up with something like:
template<class...Ts>
void Call( void(*pf)(Ts...), std::vector<Arg> const& v ) {
if (sizeof...(Ts)>v.size())
throw std::invalid_argument("");
auto f = my_wrap(pf);
call( std::move(f), v );
}
Dealing with the throws is left as an exercise, as is handling return values.
This code has not been compiled or tested, but the design should be sound. It only supports calling function pointers -- calling generalized callable objects is tricky, because counting how many arguments they want (of type int or double) is tricky. If you passed in how many arguments they want as a compile-time constant, it is easy. You could also build a magic switch that handles counts up to some constant (10, 20, 1000, whatever), and dispatch the runtime length of the vector into a compile time constant that throws on a argument length mismatch.
This is trickier.
The hard coded pointers sort of suck.
template<class...Ts>struct types{using type=types;};
template<size_t I> using index=std::integral_constant<size_t, I>;
template<class T, class types> struct index_in;
template<class T, class...Ts>
struct index_in<T, types<T,Ts...>>:
index<0>
{};
template<class T, class T0, class...Ts>
struct index_in<T, types<T0,Ts...>>:
index<1+index_in<T, types<Ts...>>{}>
{};
is a package of types.
Here is how we can store buffers:
template<class types>
struct buffers;
template<class...Ts>
struct buffers<types<Ts...>> {
struct raw_view {
void* start = 0;
size_t length = 0;
};
template<class T>
struct view {
T* start = 0;
T* finish = 0;
view(T* s, T* f):start(s), finish(f) {}
size_t size() const { return finish-start; }
T& operator[](size_t i)const{
if (i > size()) throw std::invalid_argument("");
return start[i];
}
}
std::array< raw_view, sizeof...(Ts) > views;
template<size_t I>
using T = std::tuple_element_t< std::tuple<Ts...>, I >;
template<class T>
using I = index_of<T, types<Ts...> >;
template<size_t I>
view<T<I>> get_view() const {
raw_view raw = views[I];
if (raw.length==0) { return {0,0}; }
return { static_cast<T<I>*>(raw.start), raw.length/sizeof(T) };
}
template<class T>
view<T> get_view() const {
return get_view< I<T>{} >();
}
template<class T>
void set_view( view<T> v ) {
raw_view raw{ v.start, v.finish-v.start };
buffers[ I<T>{} ] = raw;
}
};
now we modify Call:
template<class R, class...Args, size_t...Is, class types>
R internal_call( R(*f)(Args...), std::vector<size_t> const& indexes, buffers<types> const& views, std::index_sequence<Is...> ) {
if (sizeof...(Args) != indexes.size()) throw std::invalid_argument("");
return f( views.get_view<Args>()[indexes[Is]]... );
}
template<class R, class...Args, size_t...Is, class types>
R Call( R(*f)(Args...), std::vector<size_t> const& indexes, buffers<types> const& views ) {
return internal_call( f, indexes, views, std::index_sequence_for<Args...>{} );
}
which is C++14, but most components can be translated to C++11.
This uses O(1) array lookups, no maps. You are responsible for populating buffers<types> with the buffers, sort of like this:
buffers<types<double, int>> bufs;
std::vector<double> d = {1.0, 3.14};
std::vector<int> i = {1,2,3};
bufs.set_view<int>( { i.data(), i.data()+i.size() } );
bufs.set_view<double>( { d.data(), d.data()+d.size() } );
parameter mismatch counts and index out of range generate thrown errors. It only works with raw function pointers -- making it work with anything with a fixed (non-template) signature is easy (like a std::function).
Making it work with an object with no signature is harder. Basically instead of relying on the function called for the arguments, you instead build the cross product of the types<Ts...> up to some fixed size. You build a (large) table of which of these are valid calls to the passed in call target (at compile time), then at run time walk that table and determine if the arguments passed in are valid to call the object with.
It gets messy.
This is why my above version simply asks for indexes, and deduces the types from the object being called.
I have a partial solution, using C++11 grammar.
First I make a function overloader accepting arbitrator kinds of arguments
template< typename Function >
struct overloader : Function
{
overloader( Function const& func ) : Function{ func } {}
void operator()(...) const {}
};
template< typename Function >
overloader<Function> make_overloader( Function const& func )
{
return overloader<Function>{ func };
}
then, using the overloader to deceive the compiler into believing the following code ( in switch-case block )is legal:
template <typename F>
void Call( F const& f, const vector<Arg>& args )
{
struct converter
{
Arg const& arg;
operator double&() const
{
assert( arg.type == Double );
return doubles[arg.index];
}
operator int() const
{
assert( arg.type == Int );
return ints[arg.index];
}
converter( Arg const& arg_ ): arg( arg_ ) {}
};
auto function_overloader = make_overloader( f );
unsigned long const arg_length = args.size();
switch (arg_length)
{
case 0 :
function_overloader();
break;
case 1 :
function_overloader( converter{args[0]} );
break;
case 2 :
function_overloader( converter{args[0]}, converter{args[1]} );
break;
case 3 :
function_overloader( converter{args[0]}, converter{args[1]}, converter{args[2]} );
break;
/*
case 4 :
.
.
.
case 127 :
*/
}
}
and test it this way:
void test_1()
{
Call( []( int a, double& b ){ b = a; }, vector<Arg>{ Arg{Int, 3}, Arg{Double, 2} } );
}
void test_2()
{
Call( []( double& b ){ b = 3.14; }, vector<Arg>{ Arg{Double, 0} } );
}
void my_copy( int a, double& b, double& c )
{
b = a;
c = a+a;
}
void test_3()
{
//Call( my_copy, vector<Arg>{ Arg{Int, 4}, Arg{Double, 3}, Arg{Double, 1} } ); // -- this one does not work
Call( []( int a, double& b, double& c ){ my_copy(a, b, c); }, vector<Arg>{ Arg{Int, 4}, Arg{Double, 3}, Arg{Double, 1} } );
}
the problems with this solution is:
g++5.2 accept it, clang++6.1 doesn's
when the argument(s) of function Call is/are not legal, it remains silent
the first argument of function Call cannot be a C-style function, one must wrap that into a lambda object to make it work.
the code is available here - http://melpon.org/wandbox/permlink/CHZxVfLM92h1LACf -- for you to play with.
First of all, you need some mechanism to register your argument values that are later referenced by some type and an index:
class argument_registry
{
public:
// register a range of arguments of type T
template <class T, class Iterator>
void register_range(Iterator begin, Iterator end)
{
// enclose the range in a argument_range object and put it in our map
m_registry.emplace(typeid(T), std::make_unique<argument_range<T, Iterator>>(begin, end));
}
template <class T>
const T& get_argument(size_t idx) const
{
// check if we have a registered range for this type
auto itr = m_registry.find(typeid(T));
if (itr == m_registry.end())
{
throw std::invalid_argument("no arguments registered for this type");
}
// we are certain about the type, so downcast the argument_range object and query the argument
auto range = static_cast<const argument_range_base1<T>*>(itr->second.get());
return range->get(idx);
}
private:
// base class so we can delete the range objects properly
struct argument_range_base0
{
virtual ~argument_range_base0(){};
};
// interface for querying arguments
template <class T>
struct argument_range_base1 : argument_range_base0
{
virtual const T& get(size_t idx) const = 0;
};
// implements get by querying a registered range of arguments
template <class T, class Iterator>
struct argument_range : argument_range_base1<T>
{
argument_range(Iterator begin, Iterator end)
: m_begin{ begin }, m_count{ size_t(std::distance(begin, end)) } {}
const T& get(size_t idx) const override
{
if (idx >= m_count)
throw std::invalid_argument("argument index out of bounds");
auto it = m_begin;
std::advance(it, idx);
return *it;
}
Iterator m_begin;
size_t m_count;
};
std::map<std::type_index, std::unique_ptr<argument_range_base0>> m_registry;
};
Than we define a small type to combine a type and a numerical index for referencing arguments:
typedef std::pair<std::type_index, size_t> argument_index;
// helper function for creating an argument_index
template <class T>
argument_index arg(size_t idx)
{
return{ typeid(T), idx };
}
Finally, we need some template recursion to go through all expected arguments of a function, check if the user passed an argument of matching type and query it from the registry:
// helper trait for call function; called when there are unhandled arguments left
template <bool Done>
struct call_helper
{
template <class FuncRet, class ArgTuple, size_t N, class F, class... ExpandedArgs>
static FuncRet call(F func, const argument_registry& registry, const std::vector<argument_index>& args, ExpandedArgs&&... expanded_args)
{
// check if there are any arguments left in the passed vector
if (N == args.size())
{
throw std::invalid_argument("not enough arguments");
}
// get the type of the Nth argument
typedef typename std::tuple_element<N, ArgTuple>::type arg_type;
// check if the type matches the argument_index from our vector
if (std::type_index{ typeid(arg_type) } != args[N].first)
{
throw std::invalid_argument("argument of wrong type");
}
// query the argument from the registry
auto& arg = registry.get_argument<arg_type>(args[N].second);
// add the argument to the ExpandedArgs pack and continue the recursion with the next argument N + 1
return call_helper<std::tuple_size<ArgTuple>::value == N + 1>::template call<FuncRet, ArgTuple, N + 1>(func, registry, args, std::forward<ExpandedArgs>(expanded_args)..., arg);
}
};
// helper trait for call function; called when there are no arguments left
template <>
struct call_helper<true>
{
template <class FuncRet, class ArgTuple, size_t N, class F, class... ExpandedArgs>
static FuncRet call(F func, const argument_registry&, const std::vector<argument_index>& args, ExpandedArgs&&... expanded_args)
{
if (N != args.size())
{
// unexpected arguments in the vector
throw std::invalid_argument("too many arguments");
}
// call the function with all the expanded arguments
return func(std::forward<ExpandedArgs>(expanded_args)...);
}
};
// call function can only work on "real", plain functions
// as you could never do dynamic overload resolution in C++
template <class Ret, class... Args>
Ret call(Ret(*func)(Args...), const argument_registry& registry, const std::vector<argument_index>& args)
{
// put the argument types into a tuple for easier handling
typedef std::tuple<Args...> arg_tuple;
// start the call_helper recursion
return call_helper<sizeof...(Args) == 0>::template call<Ret, arg_tuple, 0>(func, registry, args);
}
Now you can use it like this:
int foo(int i, const double& d, const char* str)
{
printf("called foo with %d, %f, %s", i, d, str);
// return something
return 0;
}
int main()
{
// prepare some arguments
std::vector<int> ints = { 1, 2, 3 };
std::vector<double> doubles = { 10., 20., 30. };
std::vector<const char*> str = { "alpha", "bravo", "charlie" };
// register them
argument_registry registry;
registry.register_range<int>(ints.begin(), ints.end());
registry.register_range<double>(doubles.begin(), doubles.end());
registry.register_range<const char*>(str.begin(), str.end());
// call function foo with arguments from the registry
return call(foo, registry, {arg<int>(2), arg<double>(0), arg<const char*>(1)});
}
Live example: http://coliru.stacked-crooked.com/a/7350319f88d86c53
This design should be open for any argument type without the need to list all the supported types somewhere.
As noted in the code comments, you cannot call any callable object like this in general, because overload resolution could never be done at runtime in C++.
Instead of clarifying the question, as I requested, you have put it up for bounty. Except if that really is the question, i.e. a homework assignment with no use case, just exercising you on general basic programming, except for that only sheer luck will then give you an answer to your real question: people have to guess about what the problem to be solved, is. That's the reason why nobody's bothered, even with the bounty, to present a solution to the when-obvious-errors-are-corrected exceedingly trivial question that you literally pose, namely how to do exactly this:
vector<int> ints;
vector<double> doubles;
struct Arg {
enum Type {
Int,
Double
};
Type type;
int index;
};
template <typename F>
void Call(const F& f, const vector<Arg>& args) {
// TODO:
// - First assert that count and types or arguments of <f> agree with <args>.
// - Call "f(args)"
}
// Example:
void copy(int a, double& b) {
b = a;
}
int test() {
Call(copy, {{Int, 3}, {Double, 2}}); // copy(ints[3], double[2]);
}
In C++11 and later one very direct way is this:
#include <assert.h>
#include <vector>
using std::vector;
namespace g {
vector<int> ints;
vector<double> doubles;
}
struct Arg {
enum Type {
Int,
Double
};
Type type;
int index;
};
template <typename F>
void Call(const F& f, const vector<Arg>& args)
{
// Was TODO:
// - First assert that count and types or arguments of <f> agree with <args>.
assert( args.size() == 2 );
assert( args[0].type == Arg::Int );
assert( int( g::ints.size() ) > args[0].index );
assert( args[1].type == Arg::Double );
assert( int( g::doubles.size() ) > args[1].index );
// - Call "f(args)"
f( g::ints[args[0].index], g::doubles[args[1].index] );
}
// Example:
void copy(int a, double& b)
{
b = a;
}
auto test()
{
Call(copy, {{Arg::Int, 3}, {Arg::Double, 2}}); // copy(ints[3], double[2]);
}
namespace h {}
auto main()
-> int
{
g::ints = {000, 100, 200, 300};
g::doubles = {1.62, 2.72, 3.14};
test();
assert( g::doubles[2] == 300 );
}
There are no particularly relevant new features in C++14.
I propose this answer following my comment on your question. Seeing that in the requirements, you stated:
Preferably we should not be required to create a struct that
enumerates all the types we want to support.
It could suggests you would like to get rid of the type enumerator in your Arg structure. Then, only the value would be left: then why not using plain C++ types directly, instead of wrapping them ?
It assumes you then know all your argument types at compile time
(This assumption could be very wrong, but I did not see any requirement in your question preventing it. I would be glad to rewrite my answer if you give more details).
The C++11 variadic template solution
Now to the solution, using C++11 variadic templates and perfect forwarding. In a file Call.h:
template <class F, class... T_Args>
void Call(F f, T_Args &&... args)
{
f(std::forward<T_Args>(args)...);
}
Solution properties
This approach seems to satisfy all your explicit requirements:
Works with C++11 standard
Checks that count and types or arguments of f agress with args.
It actually does that early, at compile time, instead of a possible runtime approach.
No need to manually enumerate the accepted types (actually works with any C++ type, be it native or user defined)
Not in your requirement, but nice to have:
Very compact, because it leverage a native features introduced in C++11.
Accepts any number of arguments
The type of the argument and the type of the corresponding f parameter do not have to match exactly, but have to be compatible (exactly like a plain C++ function call).
Example usage
You could test it in a simple main.cpp file:
#include "Call.h"
#include <iostream>
void copy(int a, double& b)
{
b = a;
}
void main()
{
int a = 5;
double b = 6.2;
std::cout << "b before: " << b << std::endl;
Call(copy, a, b);
std::cout << "b now: " << b << std::endl;
}
Which would print:
b before: 6.2
b now: 5
I am trying to create a template function that is overloaded for pointer and non pointers. I did this and it works.
template<class D, class V>
bool Same(D d, V v){ return d == v; }
template<class D, class V>
bool Same(D* d, V v) { return *d==v;}
Now I want to extend it such that a templated container is a paramater and there must be one version for the container with pointer and other with the container for non pointers. I am not able to figure it out. I tried this but it won't work.
template< template<class> class Container, class Data, class Value>
bool func(Container<Data> &c, Value v)
{
return c[0] == v;
}
template< template<class> class Container, class Data, class Value>
bool func(Container<Data*> &c, Value v)
{
return *c[0] == v;
}
The error c2040 says int* differs in level of indirection from int and points to the first function.
How can I get it to work?
Rest of thecode
template<class D>
class Vec
{
std::vector<D> m_vec;
public:
void push_back(D d) { m_vec.push_back(d); }
D operator[](int i) { return m_vec[i]; }
};
void test_template()
{
Same<int, int>(2,3);
Info i = {4};
Same<Info, int>(i, 2);
Info ii = {2 };
Info *pi = ⅈ
Same<Info, int>(pi, 2);
Vec<int> iv;
iv.push_back(3);
func<Vec, int, int>(iv, 3);
Vec<int*> pv;
pv.push_back(new int(3));
func<Vec, int*, int>(pv, 3);
}
For the second call to func, the second template parameter should just be int, not int *. Otherwise, the second func declaratino will look for a Vec<int **> as the first template argument (since it has its own pointer).
func<Vec, int, int>(pv, 3);
EDIT: as DyP mentioned, you can also leave out the template arguments completely, as the compiler should be able to deduce them from the actual function arguments.