C++ templates are generally assimilated to creators of bloat, and the Shim idea deals with exactly that: making the template just a thin wrapper over a regular function. It's a really great way to cut down on the bloat.
For example, let's use a simple shim:
//
// Shim interface
//
struct Interface {
virtual void print(std::ostream& out) const = 0;
}; // struct Interface
std::ostream& operator<<(std::ostream& out, Interface const& i) {
i.print(out);
return out;
}
template <typename T>
struct IT: public Interface {
IT(T const& t): _t(t) {}
virtual void print(std::ostream& out) const { out << _t; }
T const& _t;
};
template <typename T>
IT<T> shim(T const& t) { return IT<T>(t); }
Now, I can use it like so:
void print_impl(Interface const& t);
template <typename T>
void print(T const& t) { print_impl(shim(t)); }
And no matter how print_impl is implemented, print remains very lightweight and should be inlined. Easy peasy.
C++11 however introduces variadic templates. The typical urge then is to reimplement all unsafe C-variadics with C++11 variadic templates, even Wikipedia suggests so with a printf implementation.
Unfortunately, Wikipedia's implementation does not deal with positional arguments: the kind that allows you to specify print the 3rd parameter there, etc... It would be easy, if only we had a function with this prototype:
void printf_impl(char const* format, Interface const* array, size_t size);
or similar.
Now, how do we bridge from the original interface:
template <typename... T>
void printf(char const* format, T const&... t);
to the signature above ?
One difficulty with the shims is that they rely on the binding to const-ref behavior to extend the lifetime of the temporary wrapper created just enough without having to allocate memory dynamically (they would not be cheap if they did).
It seems difficult though to get that binding + the array transformation in one step. Especially because arrays of references (and pointer to references) are not allowed in the language.
I have a beginning of a solution, for those interested:
//
// printf (or it could be!)
//
void printf_impl(char const*, Interface const** array, size_t size) {
for (size_t i = 0; i != size; ++i) { std::cout << *(array[i]); }
std::cout << "\n";
}
template <typename... T>
void printf_bridge(char const* format, T const&... t) {
Interface const* array[sizeof...(t)] = { (&t)... };
printf_impl(format, array, sizeof...(t));
}
template <typename... T>
void printf(char const* format, T const&... t) {
printf_bridge(format, ((Interface const&)shim(t))...);
}
however you will note the introduction of a supplementary step, which is a bit annoying. Still, it appears to work.
I would be very grateful if someone had a better implementation to propose.
#Potatoswatter suggested using initializer lists, which helps a bit (no range-for there).
void printf_impl(char const*, std::initializer_list<Interface const*> array) {
for (Interface const* e: list) { std::cout << *e; }
std::cout << "\n";
}
template <typename... T>
void printf_bridge(char const* format, T const&... t) {
printf_impl(format, {(&t)...});
}
But still does not solve the intermediate function issue.
Making it lightweight hinges on eliminating the type parameterization. Your shim potentially instantiates something heavy-duty with the expression out << _t, so it might not really be a good example.
C varargs handles the problem by implicitly casting everything to intptr_t. If you only want to replicate C printf functionality, you can do the same with reinterpret_cast and an initializer_list.
template <typename... T>
void printf(char const* format, T const&... t) {
printf_impl(format, { reinterpret_cast< std::intptr_t >( t ) ... } );
}
This is obviously suboptimal, but shims are inherently limited. You could do something else with polymorphic types in the initializer_list if you wanted.
In any case, this is exactly what initializer_list is meant for. It can only be constructed from a braced-init-list, making its size a compile-time constant. But the size can only be read back as a runtime constant. So its only practical use is to funnel templates differing only in list length to a common, variable-length implementation.
Add to that the lifetime semantics of initializer_list arguments — the objects are created in a contiguous array on the stack and die when the function call statement ends — and initializer_list looks a lot like <varargs>! (Edit: or your solution, which I have now actually gone back and read :vP )
Edit: Since containers can't directly store polymorphic objects, and smart pointers aren't appropriate for temporary argument objects, implementing polymorphism would require taking pointers to temporaries. Ugly, but legal due to the lifetime guaranteed for temporary objects:
template <typename... T>
void printf(char const* format, T const&... t) {
printf_impl(format, std::initializer_list< Interface const * >
{ & static_cast< Interface const & >( shim(t) )... } );
}
If you can use homogenous (same size and alignment in memory) types take a look at that:
// thin template layer over regular class/methods
template< typename T, typename... Contracts>
inline void Container::bindSingleAs(){
isMultiBase< T, Contracts...>(); //compile time test
priv::TypeInfoP types[ sizeof...( Contracts)]
{ &typeid( Contracts)... };
priv::SharedUpcastSignature upcasts[ sizeof...( Contracts)]
{ &priv::shared_upcast< T, Contracts>... };
// dispatch over non-template method.
container->bindSingleAs( &typeid(T), types, upcasts, sizeof...( Contracts));
}
Now after editing due to comments, I think there are 2 conflicting requisites.
Want an array parameter
Want no copy overhead
If the printf_impl function require an array as parameter, then this mean that the array elements should have the same disposition in memory (that means that if 1 element is 64 bytes that forces all other elements to be 64 bytes aligned even if they are 1 byte..) hence a copy is necessary, or at least the copy to a pointer to a fixed location, so it is definitely NOT POSSIBLE do what OP wanted.
We can still build that array but we are constrained:
We Don't want copying at all, then we should statically declare the type of the array, this force us to build a third type.
auto Array = MakeArray( /* values*/);
printf( Array);
We accept copying, so we build the array inside the function, since values are not known we can hide array from user but we have to copy the parameters to fixed memory locations, however we still have the array hided under the hood.
Heap allocation, that allows to pass parameters in a very compact array, however the parameters have to reside elsewhere and heap allocation may be costly.
The first solution is to accept an extra complexity in coding by creating a statically typed array wich elements can be addressed (all aligned to biggest element), however that is suboptimal since that increase the size of the object wich can hit anyway performance (if that array lives even after the function call)
The second solution hides the complexity behind the template interface, however it cannot avoid the performance cost of copying values temporarily to an array identical to the one of the first solution.
So, it is not possible doing so, sorry. The other answer falls between number 2 and 3. All other possible answers would be within one of the 3 categories.
Related
I'm working on a program where some data is statically allocated and some is dynamically allocated. Now I want to have another type that can be called with any template of the type as its argument.
#include <array>
#include <vector>
template <int size> class Foo {
std::array<int, size> data;
public:
int& operator[](std::size_t idx) {return data[idx];}
};
template <> class Foo<-1> {
std::vector<int> data;
public:
int& operator[](std::size_t idx) {return data[idx];}
};
// option 1- polymorphism
struct FooCaller {
virtual void operator()(Foo data) = 0; // how would I make this work with both forms of Foo?
};
// option 2- generic programming
template <class T> concept CanCallFoo = requires (const T& t) {
t(std::declval<Foo&>()); // how do I ensure that this can call any overload of Foo?
};
Both methods would be fine, but I'm not sure how to go about this. Because the full code is more complex, I'd rather not have both Foos inherit from a base.
A callable F could write a restriction that it can be called by Foo<x> such that an arbitrary function of x must be true to be valid.
In order for your "can be called with any Foo" test to work, you would have to invert an arbitrary function at compile time.
There is no practical way to do this short of examinjng all 2^32 possible values of x. No, really. The problem you have is that the type F is possibly too powerful for you to determine its properties. This is related to Halt and Rice's theorem and the fact that template metaprogramming and C++ overload resolution is Turing complete (only related, because 2^32 is finite).
In the other case, you could type erase. Write a type RefAnyFoo/AnyFooValue that can be constructed from any Foo type and "type erases" the operations you want, like how std::function<void(int)> type erases. It could either duck type the Foo or actually restrict to instsnces of types made from the template.
Then your interface is one that takes a AnyFooValue/RefAnyFoo (depending if you are talking about copies or references).
Now, flipping this over, you can write a concept that accepts F that take RefFooAny. This isn't quite what you asked for, but plausibly you have an X/Y problem; you had a real problem, came up with incomplete solutions, then asked about how to get your solutions working, instead of the original problem.
Similarly, it is possible you only care about certain ducktype properties of Foo<?> and not the specific type. Then a concept that checks those ducktypes could be used by your callable; this again deosn't solve your problem, as much as it flips it upside down, because you cannot verify a callable accepts an entire concept from outside the callable.
I recently wrote about the function of class member function callbacks. I need to save the callback object and function pointer, then call the function pointer and fill in the appropriate parameters where the callback is needed.
I started out as a form of typedef void (AAA::*Function)(int a, int b);, but when I need to support different parameter lists of member function, I obviously need a dynamic way to implement it.
class AAA
{
public:
int add(int a, int b)
{
return (a + b);
}
};
class BBB
{
public:
void setValue(std::string value)
{
this->value = value;
}
private:
std::string value;
};
class CCC
{
public:
void bind(??? p) // Binding objects and callback functions.
{
this->p = p;
}
template <class... Args>
auto callback(Args&&... args) // Autofill parameter list.
{
return this->p(std::forward<Args>(args)...);
}
private:
??? p; // How is this function pointer implemented?
};
int main()
{
AAA aaa;
BBB bbb;
CCC ccc;
ccc.bind(???(aaa, &AAA::add));
int number = ccc.callback(5, 6);
ccc.bind(???(bbb, &BBB::setValue));
ccc.callback("Hello");
system("pause");
return 0;
}
I don't know how can I implement the function pointer "???".
You basically are asking to have fully dynamicly typed and checked function calls.
To have fully dynamic function calls, you basically have to throw out the C++ function call system.
This is a bad idea, but I'll tell you how to do it.
A dynamicly callable object looks roughly like this:
using dynamic_function = std::function< std::any( std::vector<std::any> ) >
where use use
struct nothing_t {};
when we want to return void.
Then you write machinery that takes an object and a specific signature, and wraps it up.
template<class R, class...Args, class F>
struct dynamic_function_maker {
template<std::size_t...Is>
dynamic_function operator()(std::index_sequence<Is...>, F&& f)const {
return [f=std::forward<F>(f)](std::vector<std::any> args)->std::any {
if (sizeof...(Is) != args.size())
throw std::invalid_argument("Wrong number of arguments");
if constexpr( std::is_same< std::invoke_result_t<F const&, Args... >, void >{} )
{
f( std::any_cast<Args>(args[Is])... );
return nothing_t{};
}
else
{
return f( std::any_cast<Args>(args[Is])... );
}
};
}
dynamic_function operator()(F&& f)const {
return (*this)(std::make_index_sequence<sizeof...(Args)>{}, std::forward<F>(f));
}
};
template<class R, class...Args, class F>
dynamic_function make_dynamic_function(F f){
return dynamic_function_maker<R,Args...,F>{}(std::forward<F>(f));
}
next you'll want to deduce signatures of function pointers and the like:
template<class R, class...Args>
dynamic_function make_dynamic_function(R(*f)(Args...)){
return dynamic_function_maker<R,Args...,F>{}(std::forward<F>(f));
}
template<class Tclass R, class...Args>
dynamic_function make_dynamic_function(T* t, R(T::*f)(Args...)){
return dynamic_function_maker<R,Args...,F>{}(
[t,f](auto&&...args)->decltype(auto){return (t->*f)(decltype(args)(args)...);}
);
}
then after fixing typos above you should be able to solve your original problem.
Again, as someone who can actually write and understand the above code, I strongly advise you not to use it. It is fragile and dangerous.
There is almost never a good reason to store callbacks in places where you don't know what the arguments you are going to call it with.
There should be a different type and instance of CCC for each set of arguments you want to call it with. 99/100 times when people ask this question, they are asking the wrong question.
C++ is a type-safe language. This means that you cannot do exactly what you've outlined in your question. A pointer to a function that takes specific parameters is a different type from a pointer to a function that takes different parameters. This is fundamental to C++.
std::bind can be use to type-erase different types to the same type, but you get a single type at the end, that can be called only with a matching set of parameters (if any). It is not possible to invoke the "underlying" bound function, with its real parameters. That's because the whole purpose of std::bind is to make them disappear, and inaccessible. That's what std::bind is for.
You only have a limited set options to make this work while staying with the bounds and constraints of C++'s type-safety.
Make use of a void *, in some fashion. Actually, don't. Don't do that. That will just cause more problems, and headache.
Have a separate list and classes of callbacks, one list for each set of callbacks that take a specific set of parameters. You must know, at the point of invoking a callback, what parameters you intend to pass. So, just get your callback from the appropriate list.
Make use of std::variant. The type-safe std::variant is C++17 only (but boost has a similar template that's mostly equivalent, and available with older C++ revisions). All your callbacks take a single std::variant parameter, a variant of every possible set of parameters (designated as a std::tuple of them, or some class/struct instance). Each callback will have to decide what to do if it receives a std::variant containing the wrong parameter value.
Alternatively, the std::variant can be a variant of different std::function types, thus shifting the responsibility of type-checking to the caller, instead of each callback.
The bottom line is that C++ is fundamentally a type-safe language; and this is precisely one of the reasons why one would choose to use C++ instead of a different language that does not have the same kind of type-safety.
But being a type-safe language, that means that you have certain limitations when it comes to juggling different types together. Specifically: you can't. Everything in C++ is always, and must be, a single type.
I have a template function that I want to store a pointer to inside a std::vector.
The function looks like this:
template<typename T> void funcName(T& aT, std::vector<std::string>& fileName){...}
Now I want to store multiple pointers to functions of this kind inside a std::vector. For non-template functions I would do it like this:
typedef std::vector<std::string> string_vt;
typedef void func_t(T&, string_vt&);
typedef func_t* funcPointer;
typedef std::vector<funcPointer> funcPointer_vt;
But what is the correct syntax for template functions? How can I store them?
EDIT: First of all, thank you for your fast response. This was my first Question on Stack Overflow, so I am sorry for not providing enough information.
The set of T is finite, it can either be of type ClassA or type classB. In these function templates I want to do changes to T (so either ClassA or ClassB) with some hard coded data. I have 8 of these functions, which basically initiate a default constructed T with data specific to the function. In my program, I want to initiate 2*8 default constructed T's (8 ClassA and 8 ClassB). Therefore I run a for loop, calling one function after the other, to initiate my T objects with the function's body data.
for(int i = 0; i < initT.size(); ++i){
init_T[i]<T>(someT, fileName);
}
The for loop has as much iterations as there are function pointers inside the vector. At every iteration the function is called with some previously default constructed T and some other parameter. At the end the goal is to have 8 initiated T's with data specific to the function.
EDIT2: In case it helps, here is some actual source code. Inside the following function template I want to access my vector of function pointers in order to call the respective function.
template<typename T_Relation, typename T_Relation_Vec, bool row>
void bulk_load(initRelation_vt& aInitFunctions, T_Relation_Vec& aRel_Vec, const bool aMeasure, const uint aRuns, const char* aPath)
{
for(size_t i = 0; i < aRuns; ++i)
{
MemoryManager::freeAll();
aRel_Vec.clear();
string_vt fileNames;
for(size_t j = 0; j < aInitFunctions.size(); ++j)
{
aRel_Vec.emplace_back(T_Relation());
aInitFunctions[j]<T_Relation>(aRel_Vec[j], fileNames);
BulkLoader bl(fileNames[j].c_str(), tuples, aRel_Vec[j], delimiter, seperator);
Measure lMeasure;
if(aMeasure)
{
lMeasure.start();
}
try
{
bl.bulk_load();
if(row)
{
BulkInsertSP bi;
bi.bulk_insert(bl, aRel_Vec[j]);
}
else
{
BulkInsertPAX bi;
bi.bulk_insert(bl, aRel_Vec[j]);
}
}
catch(std::exception& ex)
{
std::cerr << "ERROR: " << ex.what() << std::endl;
}
lMeasure.stop();
if(aMeasure)
{
std::ofstream file;
file.open (aPath, std::ios::out | std::ios::app);
//print_result(file, flag, lMeasure.mTotalTime());
file.close();
}
}
}
}
This line is where the vector of function template pointers is accessed.
aInitFunctions[j]<T_Relation>(aRel_Vec[j], fileNames);
Templates are an advanced technique for static polymorphism. In a typed language, like C++, without static polymorphism you would have to separately define every entity used and precisely indicate every entity referred to.
Mechanisms of static polymorphism in C++ allow to automate indication of function or method and defer it until build via overloading. It allows you to define multiple entities sharing some characteristics at once via templates and defer definition of particular specializations until build, inferred from use.
(Notice that in various scenarios, static polymorphism allows separate code, so that changes to use and to definition are independent, which is very useful.)
The important implication of this mechanism is that every specialization of your template may be of different type. It is unclear, as of when I'm responding, whether you want to store pointers to a single or multiple types of specialization in one type of container. The possibilities depend also on parameter and result types of the function template.
A function in C++ has a type that is a combination of list of its parameter types and its return type. In other words, two functions that take and return the same types are of the same type. If your function template neither took or returned template parameter type (ie. T) nor templated type (eg. std::vector<T>), every specialization of this function template would be taking and returning the same types and would therefore be a function of the same type.
template <typename T>
int func() { ... }
This (arguably useless) function template takes no arguments and returns int, whatever T is used to specialize the template. Therefore a pointer to it could be used wherever the parameter is defined as int (*f)(). In this case you could keep pointer to any specialization in one vector.
typedef std::vector<std::string> string_vt;
typedef int func_t();
typedef func_t* funcPointer;
typedef std::vector<funcPointer> funcPointer_vt;
funcPointer x = &func<int>;
funcPointer y = &func<float>;
As can be seen, every specialization of your function template is of the same type and both pointers fit in the same container.
Next case - what if function header depends on a template parameter? Every specialization would have a different signature, that is a different function type. The pointers to all of them would be of different types - so it wouldn't be possible to even typedef this pointer once.
template <typename T>
void func(std::vector<T> param) { ... }
In this case function template specialization is of different type depending on T used to specialize.
typedef int func_t_int(std::vector<int>);
typedef func_t_int* funcPointerInt;
typedef std::vector<funcPointerInt> funcPointerInt_vt;
typedef float func_t_float(std::vector<float>);
typedef func_t_float* funcPointerFloat;
typedef std::vector<funcPointerFloat> funcPointerFloat_vt;
funcPointerInt x = &func<int>;
funcPointerFloat x = &func<float>;
Specializations are of different types, because they take different type of vectors. Pointers do not fit in the same container.
It's mention-worthy at this point, that in this case it's not necessary to define every pointer type separately. They could be a template type:
template <typename T>
using funcPointer = void (*)(std::vector<T>);
Which now allows funcPointer<int> to be used as a type qualifier, in place of earlier funcPointerInt.
funcPointer<float> y = &func<float>;
In more complicated situations a template could be created, whose every specialization is of a different type, and then would use a single instance of concrete vector to store various pointers to functions of type of only one of the specializations of your template. Although a simple template like in the example can only produce a single function per type, because every specialization yields one type of function and one function of that type, it's not impossible to conceive a scenario where various pointers to functions are obtained, both to specializations and usual functions, perhaps from various sources. So the technique could be useful.
But yet another scenario is that despite every specialization of the template being of different type, there's a need to store pointers to various specializations in single std::vector. In this case dynamic polymorphism will be helpful. To store values of different types, fe. pointers to functions of different types, in one type of variable, requires inheritance. It is possible to store any subclass in a field defined as superclass. Note however, that this is unlikely to accomplish anything really and probably not what you're really looking for.
I see two general possibilities now. Either use a class template with a method, which inherits from a non-template class.
template <typename T>
class MyClass : BaseClass
{
public:
T operator()(const T& param, int value);
}
MyClass<int> a;
MyClass<float> b;
BaseClass* ptr = &a;
ptr = &b;
While every specialization of this class may be of a different type, they all share superclass BaseClass, so a pointer to a BaseClass can actually point to any of them, and a std::vector<funcPointerBase> can be used to store them. By overloading operator() we have create an object that mimics a function. The interesting property of such a class is that it can have multiple instances created with parameter constructors. So effectively class template produces specializations of multiple types, and in turn every specialized class can produce instances of varying parametrization.
template <typename T>
class MyClass : BaseClass
{
int functor_param;
public:
MyClass(int functor_param);
T operator()(const T& param, int value);
}
This version allows creation of instances that work differently:
MyClass<int> a(1);
MyClass<int> b(2);
MyClass<float> c(4);
MyClass<int>* ptr = &a;
ptr = &b;
ptr = &c;
I am no expert on functors, just wanted to present the general idea. If it seems interesting, I suggest researching it now.
But technically we're not storing function pointers, just regular object pointers. Well, as stated before, we need inheritance to use one type of variable to store values of various types. So if we're not using inheritance to exchange our procedural functions for something dynamically polymorphic, we must do the same to pointers.
template <typename T>
T func(std::pair < T, char>) {}
template <typename T>
using funcPointer = T(*)(std::pair<T, char>);
template <typename T>
class MyPointer : BasePointer
{
funcPointer<T> ptr;
public:
MyPointer(funcPointer<T> ptr);
T()(std::pair <T, char>) operator*(std::pair <T, char> pair)
{
*ptr(pair);
}
};
This, again, allows creation of single std::vector<BasePointer> to store all possible pseudo-function-pointers.
Now the very important bit. How would You go about calling those, in either scenario? Since in both cases they are stored in a single std::vector<>, they are treated as if they were of the base type. A specific function call needs parameters of specific type and returns a specific type. If there was anything that all subclasses can do in the same way, it could be exposed by defining such a method in base class (in either scenario using functors or pointer..ors?), but a specific specialized function call is not that kind of thing. Every function call that You would want to perform in the end, after all this struggle, would be of a different type, requiring different type of parameters and/or returning different type of value. So they could never all fit into the same place in usual, not templated code, the same circumstances in execution. If they did, then dynamic polymorphism wouldn't be necessary to solve this problem in the first place.
One thing that could be done - which is greatly discouraged and probably defeats the purpose of dynamic polymorphism - is to detect subclass type at runtime and proceed accordingly. Research that, if you're convinced you have a good case for using this. Most likely though, it's probably a big anti-pattern.
But technically, anything you may want to do is possible somehow.
If I have correctly understood you, I may have a really simple and efficient solution:
template<class...Ts>
struct functor{
//something like a dynamic vtable
std::tuple<void(*)(Ts&,std::vector<std::string>&)...> instantiated_func_ptr;
template<class T>
void operator ()(T& aT,std::vector<std::string>& fileName){
get<void(*)(T&,std::vector<std::string>&)>(instantiated_func_ptr)
(aT,fileName);
}
};
Voilà!!
Until c++17, get<typename> is not defined so we have to define it (before the definition of the template functor above):
template<class T,class...Ts>
struct find_type{
//always fail if instantiated
static_assert(sizeof...(Ts)==0,"type not found");
};
template<class T,class U,class...Ts>
struct find_type<T,U,Ts...>:std::integral_constant<size_t,
find_type<T,Ts...>::value+1>{};
template<class T,class...Ts>
struct find_type<T,T,Ts...>:std::integral_constant<size_t,0>{};
template<class T,class...Ts>
constexpr decltype(auto) get(const std::tuple<Ts...>& t){
return get<find_type<T,Ts...>::value>(t);
}
And an example to show how to use it:
struct A{
void show() const{
std::cout << "A" << "\n";
}
};
struct B{
void show() const{
std::cout << "B" << "\n";
}
};
template<class T>
void func1(T& aT,std::vector<std::string>& fileName){
std::cout << "func1: ";
aT.show();
}
template<class T>
void func2(T& aT,std::vector<std::string>& fileName){
std::cout << "func2: ";
aT.show();
}
template<class T>
void func3(T& aT,std::vector<std::string>& fileName){
std::cout << "func3: ";
aT.show();
}
using functorAB = functor<A,B>;
int main(){
auto functor1=functorAB{{func1,func1}};//equivalent to functorAB{{func1<A>,func1<B>}}
auto functor2=functorAB{{func2,func2}};
auto functor3=functorAB{{func3,func3}};
auto v=std::vector<functorAB>{functor1,functor2,functor3};
auto a=A{};
auto b=B{};
auto fileNames = std::vector<std::string>{"file1","file2"};
for(auto& tf:v)
tf(a,fileNames);
for(auto& tf:v)
tf(b,fileNames);
}
In practice it is just a reproduction of the virtual call mechanism,
the tuple in functor is kind of virtual table. This code is not
more efficient than if you had written an abstract functor with virtual
operator() for each of your class A and B and then implemented it for each of
your functions... but it is much more concise, easier to maintain and may produce less binary code.
The problem: I find myself faced with numerous duplicate functions to support different types of almost-identical array-like inputs. For example, a function foo might be available in the following versions:
void foo (int v); // single value, 99% of all use cases.
void foo (std::initializer_list<int> v);
void foo (const std::vector<int> &v);
void foo (int *v, int size);
This duplication bothers me. I would like to have a single function foo, that may be called with any kind of array-like data (with a single value obviously being seen as an array of size 1).
Possible solutions include:
Always use the vector version. This incurs some overhead for memory allocation on every use, and since 99% of my uses are for single values I find this undesirable.
Have an interface specifying an iterator pair. This again falls flat when attempting to call the function for a single value.
Have some sort of abstraction for array-like data that can handle all of the desired input types. This is a promising approach, but I do run into some trouble...
My implementation is called mem_range, which presents a vector-like interface (only including operations that do not change the size of the vector, obviously). The various types of arrays are supposed to be handled through different constructors of mem_range.
I have trouble specifying the constructor that is supposed to take std::array. The problem is the array size, which is part of the template definition - I cannot figure out how to create a constructor that will accept arrays of any size.
template<typename T>
class mem_range {
public:
mem_range (T *begin, T *end) { } // ok
mem_range (std::vector<T> &vec) { } // ok
template<int array_size>
mem_range<array_size> (std::array<T, array_size> &arr) { } // not ok
}
The last constructor yields "error C2988: unrecognizable template declaration/definition" on MSVC2015. I've gone through quite a few variations now, but nothing that makes the compiler happy.
Just to be clear, based on answers I've read on similar questions here on stackoverflow:
Resizing the array-like data in any way is not in scope. If I wanted that capability I'd just pass an std::vector.
I'm aware there are many questions with similar titles. None of these appear to have decent answers, usually getting no further than "why do you want this?".
I'm trying to make this work on MSVC2015 and modern GCC, so C++14/17 are fine (as far as supported).
When declaring the templated constructor, the template is understood to belong to the constructor function, so you don't need to specify it there.
You are also missing a closing bracket > after the array argument.
So the constructor should look like this:
template<int array_size>
mem_range(std::array<T, array_size>) { }
And of course, you should consider passing the array object as a reference to a constant, and using the correct type (see e.g. this std::array reference`), i.e.
template<std::size_t array_size>
mem_range(std::array<T, array_size> const&) { }
You can make array_size an optional value of the template class.
template<typename T, int array_size=0>
class mem_range {
public:
mem_range (T *begin, T *end) { } // ok
mem_range (std::vector<T> &vec) { } // ok
mem_range (std::array<T, array_size> &array) { }
}
I would like to call a function on all elements of a boost::fusion::vector. The elements are of types like this:
class A {
...
void print_with_prefix(const char *prefix) {
std::cout << prefix << *this;
}
};
One can call this function on each element in this way:
// Call print_with_prefix() on a boost::fusion sequence:
struct CallPrintWithPrefix {
const char *prefix_;
CallPrintWithPrefix(const char *prefix) : prefix_(prefix) {}
template <class T> void operator()(T &element) const {
element.print_with_prefix(prefix);
}
}
template <class BoostFusionVector>
void print_all(BoostFusionVector &v, const char *prefix) {
boost::fusion::for_each(v, CallPrintWithPrefix(prefix));
}
However, this implementation of print_all() including helper class is pretty ugly and seems overly complicated! Assuming C++0x is allowed, what is the right way to implement it?
What you did is the right way. C++0x can't help much in that respect because e.g. lambda expressions are not polymorphic, so at the end of the day you'll have to write a template somewhere (which unfortunately must be at namespace scope, even with C++0x), like you did with the operator().
Some libraries like Boost.Phoenix allow to create polymorphic functors on the fly though. For instance ref(std::cout) << arg1 creates an object that is capable of passing any kind of argument to std::cout. It won't help in your case since you're calling a member function.
It's the second time I'm mentioning it today, but I do have a make_overload facility that allows me to create an overloaded functor on the fly. It could help in your case if the set of element types is small and not likely to change. For instance assuming there's only two such types A and B:
auto overload = make_overload(
[prefix](A& a)
{ a.print_with_prefix(prefix); }
, [prefix](B& c)
{ b.print_with_prefix(prefix); } );
boost::fusion::for_each(v, overload);