Complex Use of Template in C++ - c++

I come across a piece of code about template:
unroller.h
template <int It, int End> struct unroller {
template <typename Action> static void step(const Action &action) {
action(std::integral_constant<int, It>());
unroller<It + 1, End>::step(action);
}
};
template <int End> struct unroller<End, End> {
template <typename Action> static void step(const Action &) {}
};
snippet of the code that show how it is invoked:
constexpr int NUM_ROWS = 2;
constexpr int NUM_COLS = 2;
int input_idx = 0;
for (int pass = 0; pass < num_passes; pass++) {
unroller<0, NUM_ROWS>::step([&input_idx, input_accessor](auto i_idx) {
constexpr int i = i_idx.value;
unroller<0, NUM_COLS>::step([&input_idx, input_accessor](auto j_idx) {
constexpr int j = j_idx.value;
ProducerToConsumerPipeMatrix::pipe_at<i, j>::write(input_accessor[input_idx++]);
});
});
}
Question:
template <typename Action> static void step(const Action &action) is function template?
what is action(std::integral_constant<int,It>());? I thought action is pass by reference. However, i don't really understand it.
I don't understand the way it invoke unroller<0, NUM_ROWS>::step([&input_idx, input_accessor](autoi_idx). My understanding is in the angle bracket <> should be data types. In this case, it pass the value. Besides, what is ::step? Then, why it can pass 2 argument in the step(...)>
I am new to c++. Can someone explain in simple way?

I think you may need to start learning templates from the beginning.
Yes. It's a typical function template
No, it's passed by value, at least in your example is passed by value.
[&input_idx, input_accessor](auto j_idx) {
constexpr int j = j_idx.value;
ProducerToConsumerPipeMatrix::pipe_at<i, j>::write(input_accessor[input_idx++]);
});
this lambda is passed into higher-order function step as its parameter, it will later receieve a std::integral_constant<int, It> prvalue temporary as the parameter of the lambda.
std::integral_constant<int,It>() constructs a temporary object of std::integral_constant<int, It>, see this: https://en.cppreference.com/w/cpp/types/integral_constant
It's not two arguments, it's lambda capture, see this: https://en.cppreference.com/w/cpp/language/lambda
the parameters of a template don't need to be types, see this: https://en.cppreference.com/w/cpp/language/templates#Syntax

I am new to c++. Can someone explain in simple way?
I'm going to try, but this is template meta-programming that usually needs some kind of expertise mixed with functional style (which is another realm of expertise).
template static void step(const Action &action) is function template?
Yes, a function in which Action is a parameter.
what is action(std::integral_constant());? I thought action is
pass by reference. However, i don't really understand it.
The general idea of unroller is to unroll a loop. This to generate automatically a sequence of calls to something like:
action(0);
action(1);
action(2);
...
action(NUM_ROWS-1);
action is then a parameter to any function that is able to get an int value.
The function used here is:
[&input_idx, input_accessor](auto i_idx) {
constexpr int i = i_idx.value;
unroller<0, NUM_COLS>::step([&input_idx, input_accessor](auto j_idx) {
constexpr int j = j_idx.value;
ProducerToConsumerPipeMatrix::pipe_at<i,j>::write(input_accessor[input_idx++]);
}
}
which itself uses the unrolling! Looks like it unrolls a computation on 2D matrix elements. Theses functions are called lambdas, anonymous functions is you prefer. Then you are in the realm of functional programming.
I don't understand the way it invoke unroller<0, NUM_ROWS>::step([&input_idx, input_accessor](autoi_idx). My
understanding is in the angle bracket <> should be data types. In this
case, it pass the value. Besides, what is ::step? Then, why it can
pass 2 argument in the step(...)>
Template parameters can be types but also values of different kind...
unroller is a template type that takes two arguments: <int It, int End>.
It and End are typed as ints not class or typename (as it is with Action).

Related

Use Variadic templates (or a similar mechanism) to pass list of types to a function

I would like to implement a class wrapper for database.
Currently, I'm working on a createTable function.
The way I have tried to make it work is, that the user specifies the types
as a template parameters, and the column names as an initialiser list,
this is the template of the function:
template <typename ... Ts>
bool createTable(const std::string & tableName, const std::initializer_list<std::string> & columnNames);
And this is the body of the method:
template<typename ... Ts>
bool DatabaseConnection::createTable(const std::string &tableName, const std::initializer_list<std::string> & columnNames)
{
constexpr size_t num_cols = sizeof...(Ts);
assert(num_cols == columnNames.size());
auto typetuple = std::tuple<Ts...>();
std::vector<std::tuple<std::string, std::string>> columnNameAndType(num_cols);
auto columnNameIterator = columnNames.begin();
for(unsigned it = 0; it++ < columnNames.size(); it++){
typedef std::tuple_element<it, typetuple>::type c; // non-type template argument is not a constant expression
if(is_same<c, int> ...) //pseudocode
std::string dbtype = "INTEGER"; //pseudocode
}
}
Sadly, the tuple_element line doesn't work, because it's not really a
constant expression.
Now, someone might ask, why I want to call it like this:
createTable<int, std::string>("Users", {"ID", "Name"});
instead of just passing two initialiser lists?
Well I just want to distance the user from the interface - If I were able to determine
the it-h type I could just use something like decltype or is_same to determine the type used in database creation query - the user just says what type he/she wants and the Database class
determines the best database type to match the user's request.
Now, it could still be made with initaliser lists, but it wouldn't be compile time, and
I'm just curious to see if it's possible at comple time.
I hope my explanation of the problem is sufficient.
Of course this is mostly a theoretical problem, but I think many people
would be interested in such a syntax, and I haven't found any solutions on the internet yet.
This interface is certainly possible.
A for loop isn't going to do it, because one statement/variable/expression/etc. can't have different types on different evaluations of a for substatement. The loop will need to be via pack expansion instead.
One or more private helper member functions could help for this. It would be possible to get it all in one function definition using a generic lambda, but a little unpleasant.
// private static
template <typename T>
std::string DatabaseConnection::dbTypeName()
{
if constexpr (std::is_same_v<T, int>)
return "INTEGER";
// ...
else
static_assert(!std::is_same_v<T,T>, "Unsupported type argument");
}
template<typename ... Ts>
bool DatabaseConnection::createTable(
const std::string &tableName,
std::initializer_list<std::string> columnNames)
{
constexpr size_t num_cols = sizeof...(Ts);
assert(num_cols == columnNames.size());
std::vector<std::tuple<std::string, std::string>> columnNameAndType;
auto columnNameIterator = columnNames.begin();
(columnNameAndType.emplace_back(*columnNameIterator++, dbTypeName<Ts>()), ...);
// ...
}

Can I use template parameter as argument to non-template method?

I am looking to move some of the code of within a template method to a non-template method in order to decrease the binary size.
There is a template class called 'Target', as illustrated below
template<TargetType K, typename V = plat_target_handle_t>
class Target
{
.............
..............
};
TargetType is an enum data type.
template<>
template< TargetType T>
std::vector<Target<T> >
Target<TARGET_TYPE_X>::getChildren(const TargetState i_state) const
{
std::vector<Target<T> > l_children;
for ( int i=0; i < elements_in_some_list ; ++i)
{
/*If the current entry in some_list match my critera, add to the l_children */
}
}
TargetType is an enum data type and TARGET_TYPE_X is one of the enum values.
I want to move all the logic to select the children to a global method, lets say getChildrenHelper.
getChildrenHelper is declared as below.
void getGhildrenHelper(const TargetType i_targetType,
const TargetState i_targetstate,
std::vector<Target<TARGET_TYPE_ALL>> & io_children);
And then the getChildren method would eventually look like
template<>
template< TargetType T>
std::vector<Target<T> >
Target<TARGET_TYPE_X>::getChildren(const TargetState i_state) const
{
std::vector<Target<T> > l_children;
childHelper(T,i_state,l_children);
return l_children;
}
My guess is this cannot be done, though the native compiler that I am working with did not through an error.
However there is another existing code where the similar concept is working perfectly fine
template< TargetType K >
inline ReturnCode putParam(const Target<K>& i_target,
const RingID i_ringID,
const RingMode i_ringMode)
{
ReturnCode l_rc = FAPI2_RC_SUCCESS;
// Find the string in the SEEPROM
l_rc = findInImageAndApply(i_target, i_ringID, i_ringMode);
return l_rc;
}
fapi2::ReturnCode findImageAndApply(
const fapi2::Target<fapi2::TARGET_TYPE_ALL>& i_target,
const RingID i_ringID,
const fapi2::RingMode i_ringMode)
{
................
................
}
It is quite common for template functions to invoke ordinary, non-template functions in order to execute a large chunk of code that does not need or use any template parameters. This is a common technique for avoiding template-generated code bloat.
In your case, TargetType appears is a template parameter, and there is no such class. As such:
void getGhildrenHelper(const TargetType i_targetType,
const TargetState i_targetstate,
std::vector<Target<TARGET_TYPE_ALL>> & io_children);
that by itself should not compile, since TargetType appears to be a template parameter, and not a class name, based on the code in your template specialization.
But, your code might be ambiguous, here. In any case, if neither TargetType and TargetState, nor Target<TARGET_TYPE_ALL> are template parameters, this would make this an ordinary function, and it can certainly be invoked from a template function, with matching parameters.
A template function can do anything that an ordinary function does, including calling other functions, or using other templates. The requirements are the same as for any other function: matching function parameter types, etc...

metaprogramming with variadic templates in C++

I am working on a simple game engine that provides a base class for game objects that can be extended with subclasses for the specific game. I need to write a function that can take a file, parse object names from it, and instantiate the corresponding objects in the game; providing a mechanism for storing level data in files. I had hoped to use metaprogramming to create a function that allows the caller to pass in a variable number of data types and generates a function that searches for names corresponding to those types in a file. Its use would look something along the lines of this (using templates):
fileParseFunction<type1, type2 type3>("filename");
would generate a function equivalent to:
fileParseFunction(string filename)
{
//code that opens file called "filename" and handles tokenizing/parsing
if(token == "type1")
{
gameWorld.add(new type1());
}
elseif(token == "type2")
{
gameWorld.add(new type2());
}
elseif(token == "type3")
{
gameWorld.add(new type3());
}
//other code to finish loading the level
}
Called with the parameter "filename". This should work for a variable number of types (3 in the example). I wrote some code to test the concept which involves generating a similar function. It uses templates to convert typename symbols to strings (this is needed for use in the comparisons in the function I eventually hope to write) and also variadic templates to generate a function that prints the names of all the types passed in as template parameters. Here it is:
#define TypeNameTemplate(a) template<> inline const char* typeName<a>(void) { return #a; }
template <typename T>
inline const char* typeName(void) { return "unknown"; }
TypeNameTemplate(int);
TypeNameTemplate(std::string);
TypeNameTemplate(double);
TypeNameTemplate(bool);
TypeNameTemplate(float);
/*template <>
inline const char* typeName<int>(void) { return "int"; }*/
template <typename T> inline void printtypes()
{
std::cout << typeName<T>();
}
template <typename T, typename... Args> void printtypes()
{
std::cout << typeName<T>() << std::endl;
printtypes<Args...>();
}
using namespace std;
int main()
{
//string a = typeName<int>();
//print();
printtypes<int, double, string, bool, float>();
return 0;
}
printtypes() should generate a function equivalent to:
void printtypes()
{
std::cout << typeName<int>();
std::cout << typeName<std:string>();
std::cout << typeName<double>();
std::cout << typeName<bool>();
std::cout << typeName<float>();
}
However, during compilation i get this error:
E:\C++ projects\templateTest\main.cpp:26:5: note: candidates are:
E:\C++ projects\templateTest\main.cpp:18:35: note: void printtypes() [with T = float]
E:\C++ projects\templateTest\main.cpp:23:46: note: void printtypes() [with T = float; Args = {}]
It appears that upon reaching the end up the variadic parameter pack recursively, the compiler does not know whether to call the template specialized on only one type with the last type in the pack, or the variadic template with the last type in the pack plus an empty parameter pack. Is what I'm attempting to do possible/practical in C++, and is there a way to let the compiler know that it should use the singe parameter template for the base/final case of the recursive call?
A simple solution is to add another explicit parameter to the second overload:
template <typename T, typename T2, typename... Args> void printtypes()
{
std::cout << typeName<T>() << std::endl;
printtypes<T2,Args...>();
}
While this answer does not answer your specific question about variadic templates, I hope it does answer your underlying question about how to make your game engine extensible.
What you came up with by creating your fileParseFunction() is an implementation of the Factory Method pattern. This is the main part that makes it easy to turn stored data into real objects. Unfortunately, it violates the Open-Close Principle making it difficult to reach your end goal, extendability.
For example, in your code above, your factory function can parse "type1", "type2" and "type3" from your data file and generate objects of type1, type2 and type3 but adding more types would mean editing this function and adding a new else if for every new type you wish to add
You've already identified this as a problem and are trying to solve it using variadic templates. Unfortunately, if you extend the number of game objects into the twenties, thirties, or even hundreds of types, variadic templates will become cumbersome to use, if at all they are able to go that far.
A much simpler solution is to use the Abstract Factory pattern. This essentially shifts responsibility for creating game objects from your file parser's Factory Function, to a factory object. Whether this transfer of power goes to a single function, or a fully-fledged class is up to you. You could also templatise this factory to save on coding.
Each of your factories will have to register their existence with the file parser before the parser is called and extending the parser's capabilities will be as simple as creating a new factory and registering it with the parser.
A simple example would be:
class GameObjectAbstractFactory {
public:
string registeredTypes() const{
// cycle through hash table to return the names of registered factories
}
GameObjectFactory* getFactory(string factoryName){
// return the registered factory, or nullptr if not registered
}
void registerFactory(string factoryName, GameObjectFactory*){
// add the factory if it doesn't exist
}
static GameObjectAbstractFactory* instance(){
// access to Singleton instance
}
private:
GameObjectAbstractFactory(); // enforces Singleton pattern
Hash<string, GameObjectFactory*> registeredFactories;
};
// Interface class for generating concrete types, can be templatised, depending on implementation
class GameObjectFactory{
public:
string name() = 0;
GameObject *createObject() = 0;
};
This would alter your parsing function so that it becomes:
fileParseFunction(string filename)
{
//code that opens file called "filename" and handles tokenizing/parsing
GameObjectAbstractFactory *abstractFactory = GameObjectAbstractFactory::instance();
GameObjectFactory *factory = abstractFactory.getFactory(token);
if(factory != nullptr)
{
gameWorld.add(factory.createObject());
}
//other code to finish loading the level
}
This would then make your fileParseFunction() compliant with the Open-Close Principle in that it could still generate new game objects as your engine is extended but the function itself will not have to be modified in order to do so.
There is a caveat with this pattern though: all the factories need to be registered with the abstract factory before they are needed, otherwise the required game object will not be able to be created.
As I mentioned in the beginning, this answer does not address your direct question about variadic templates but I hope this helps with the extendability of your game engine.

Calling the appropriate function based on an enumeration, but using templates

I have this wrapper function that is supposed to call the appropriate function on a large dataset based on the type of data it contains, like this:
void WrapperFunc( int iRealDataType, int iUseAsDataType )
{
// now call the right function based on both arguments
switch ( iRealDataType )
{
case FancyType1:
switch ( iUseAsDataType )
{
case CoolType1: DataAnalysisFunc_Fancy1_Cool1(); break;
// etc.
}
// etc.
}
}
So far, this was solved by having two nested switch statements and then calling one of the many many specialized functions for each existing combination of Real and UseAs data type. However as the number of defined types grows it is a nightmare to maintan the code base. So I decided to finally use templates. I mostly avoid them if I can, but this time they suit the problem well.
So now instead of DataAnalysisFunc_Fancy1_Cool1 i would like to call DataAnalysisFunc<FancyType1,CoolType1> ang get rid of the hundreds of lines of switch statements, BUT i cannot use it like this, since FancyType1 is an enum, not the type (which is Fancy1 for example).
Just to clarify - I know this sounds like a stupid artificial example, but I tried to simplify the problem as much as possible to get to the core of it, instead of explaining the ton of details that would go into a much more concrete example.
EDIT: my data analysis functions are in reality CUDA kernels - this will probably rule out some possible solutions. Sorry for that.
Templates sound like the wrong solution. What you want is a lookup table.
typedef void (*DataAnalysisFunc)();
const DataAnalysisFunc DataAnalysisFunctions[NumFancyTypes][NumCoolTypes] = {
/*Fancy1*/ {
/*Cool1*/ &DataAnalysisFunc_Fancy1_Cool1,
/*Cool2*/ &DataAnalysisFunc_Fancy1_Cool2 }
/*Fancy2*/ {
/*Cool1*/ &DataAnalysisFunc_ImpossibleCombination, // can't happen, throw or something
/*Cool2*/ &DataAnalysisFunc_Fancy2_Cool2 }
};
void WrapperFunc(int realDataType, int useAsDataType) {
assert(realDataType >= 0 && realDataType < NumFancyTypes);
assert(useAsDataType >= 0 && useAsDataType < NumCoolTypes);
(*DataAnalysisFunctions[realDataType][useAsDataType])();
}
Now, if those DataAnalysisFuncs share a lot of code, templates might help you there, but not for dynamic dispatch.
BUT i cannot use it like this, since FancyType1 is an enum, not the
type (which is Fancy1 for example)
You can convert enum to type, just use one of metaprogramming basic tools:
Int2Type, it is used to replace run-time branches of if statements on the compile time dispatches.
It looks like:
template <int Number>
struct Int2Type
{
enum {value};
};
Int2Type - is treated as a type, using it and function overloading - you can replace if statements.
UPDATE:
I added some example here, to make my answer more clear
1. Int2Type
// usage allows to implement dispatch in a compile time instead of branching statements in a run-time
template <int Val>
struct Int2Type
{
static const int val_= Val;
};
template <typename ItBegin, typename ItEnd>
void doSort(ItBegin it0, ItEnd it1, Int2Type<1>)
{
using namespace std;
// sort
cout << "Standart sorting algorithm was used. For iterators" << endl;
}
template <typename ItBegin, typename ItEnd>
void doSort(ItBegin it0, ItEnd it1, Int2Type<2>)
{
using namespace std;
// sort
cout << "Fast sorting algorithm was used. For pointers" << endl;
}
// based on the 3-rd dummy type parameter call will be dispatched to needed function
int arr[3];
MainTools::doSort(arr, arr + sizeof(arr) / sizeof(arr[0]), MainTools::Int2Type<1>());
vector<int> v(3);
MainTools::doSort(v.begin(), v.end(), MainTools::Int2Type<2>());
You're looking for type dispatching. I find this easiest to do with Boost.MPL.
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/at.hpp>
struct DispatchChecker
{
int iRealDataType, iUseAsDataType;
template <class T>
void operator()(T) const
{
static const int iCurrentReal = boost::mpl::at_c<T, 0>::type::value;
static const int iCurrentUseAs = boost::mpl::at_c<T, 1>::type::value;
if(iRealDataType == iCurrentReal &&
iUseAsDataType == iCurrentUseAs)
DataAnalysisFunc<iCurrentReal,iCurrentUseAs>();
}
};
typedef /*mpl sequence of all valid types*/ valid_types;
boost::mpl::for_each<valid_types>(DispatchChecker{iRealDataType,iUseAsDataType});
boost::mpl::for_each accepts a compile time sequence and instantiates and runs a functor on each element of the sequence. In this case the functor checks that the compile parameters match the runtime parameters and calls the appropriate DataAnalysisFunc when they match.
As for how to get the valid_types, the easiest way is to just write out each valid pair in a sequence like this:
typedef boost::mpl::vector<
boost::mpl::vector_c<int, 0, 0>,
boost::mpl::vector_c<int, 2, 0>,
boost::mpl::vector_c<int, 1, 1>,
boost::mpl::vector_c<int, 0, 2>,
boost::mpl::vector_c<int, 1, 2>
> valid_types;
Note:
As Sebastian Redl points out, using templates is probably only worthwhile if the DataAnalasysFuncs share a lot code between them, otherwise a runtime dispatch is probably a much better solution.

Return several arguments for another function by a single function

This question was closed as exact duplicate since I chose a misleading question title. It was not wrong but suggested an issue often discussed, e.g. in this question. Since the content is about a more specific topic never covered on Stackoverflow I would like the question to be reopened. This happened now, so here goes the question.
I have given a function expecting three integer values as parameters length(int x, int y, int z);. I cannot modify this function, e.g. to accept a struct or tuple of whatever as single parameter.
Is there a way in C++ to write another function which can be used as single argument to the function above, like length(arguments());?
Anyhow the return type of that function arguments(); seems to need to be int, int, int. But as far as far as I know I can't define and use functions like this in C++. I know that I could return a list, a tuple, a struct or a class by arguments(). The question was closed because some people thought I would have asked about this. But the difficult part is to pass the tuple, or struct, or whatever as the three given integer parameters.
Is this possible and if yes, how is that possible in C++? A solution making use of C++11 would be fine.
I don't think there is any direct way of doing what you want, but here is a C++11 technique that I use in several places of my code. The basic idea is to use a template function which I've called call_on_tuple to take a function argument f as well as a tuple of further arguments, expand the tuple and call the function on the expanded list of arguments:
template <typename Fun, typename... Args, unsigned... Is>
typename std::result_of<Fun(Args...)>::type
call_on_tuple(Fun&& f, std::tuple<Args...>&& tup, indices<Is...>)
{ return f(std::get<Is>(tup)...); }
So the idea is that instead of calling
length(arguments());
you would call
call_on_tuple(length,arguments());
This assumes that arguments() is changed so it returns a std::tuple<int,int,int> (this is basically the idea from the question you cited).
Now the difficult part is how to get the Is... argument pack, which is a pack of integers 0,1,2,... used to number the elements of the tuple.
If you are sure you'll always have three arguments, you could use 0,1,2 literally, but if the ambition is to make this work for any n-ary function, we need another trick, which has been described by other posts, for example in several answers to this post.
It's a trick to transform the number of arguments, i.e. sizeof...(Args) into a list of integers 0,1,...,sizeof...(Args):
I'll put this trick and the implementation of call_on_tuple in a namespace detail:
namespace detail {
template <unsigned... Is>
struct indices
{ };
template <unsigned N, unsigned... Is>
struct index_maker : index_maker<N-1,N-1,Is...>
{ };
template <unsigned... Is>
struct index_maker<0,Is...>
{ typedef indices<Is...> type; };
template <typename Fun, typename... Args, unsigned... Is>
typename std::enable_if<!std::is_void<typename std::result_of<Fun(Args...)>::type>::value,
typename std::result_of<Fun(Args...)>::type>::type
call_on_tuple(Fun&& f, std::tuple<Args...>&& tup, indices<Is...>)
{ return f(std::get<Is>(tup)...); }
}
Now the actual function call_on_tuple is defined in global namespace like this:
template <typename Fun, typename... Args>
typename std::enable_if<!std::is_void<typename std::result_of<Fun(Args...)>::type>::value,
typename std::result_of<Fun(Args...)>::type>::type
call_on_tuple(Fun&& f, std::tuple<Args...>&& tup)
{
using std::tuple;
using std::forward;
using detail::index_maker;
return detail::call_on_tuple
(forward<Fun>(f),forward<tuple<Args...>>(tup),typename index_maker<sizeof...(Args)>::type());
}
It basically calls detail::index_maker to generate the list of increasing integers and then calls detail::call_on_tuple with that.
As a result, you can do this:
int length(int x, int y, int z)
{ return x + y + z; }
std::tuple<int,int,int> arguments()
{ return std::tuple<int,int,int> { 1 , 2 , 3 }; }
int main()
{
std::cout << call_on_tuple(length,arguments()) << std::endl;
return 0;
}
which is hopefully close enough to what you needed.
Note. I have also added an enable_if to ensure this is only used with functions f that actually return a value. You can readily make another implementation for functions that return void.
Sorry again for closing your question prematurely.
PS. You'll need to add the following include statements to test this:
#include <tuple>
#include <type_traits>
#include <iostream>
It is not possible, C++ does not allow to provide 3 return values natively that can be used as 3 separate input arguments for another function.
But there are 'tricks' to return multiple values. Although none of these provide a perfect solution for your question, as they are not able to be used as a single argument to length() without modifying length().
Use a container object, like a struct, tuple or class
typedef struct { int a,b,c; } myContainer;
myContainer arguments(int x, int y, int z) {
myContainer result;
result.a = 1;
// etc
return result;
}
myContainer c = arguments(x, y, z);
length(c.a, c.b, c.c);
The trick is to overload the length() function, so it looks like you can use it with a single argument:
void length(myContainer c) {
length(c.a, c.b, c.c);
}
length(arguments());
Of course you could optimize it further, by using inline, macros, and what not.
I know it is still not exactly what you want, but I think this is the closest approach.
You need to declare a struct { int a, b, c; } or something similar (a class would work too) - I take it you have been programming python or php or some such.
Most programming languages would do this through some form of adapter function. That is a function that will take as argument the function to call (here length) and the arguments to call it with. You can probably build something similar in C++ with templates. Look at the functional header to get inspiration.
A language that natively provides what you are looking for is Perl. You can write:
sub arguments {
return 1, 2, 3;
}
sub length {
my ($p1, $p2, $p3) = #_;
# … Work with $p1, $p2 and $p3
}
length(arguments());
Pass in the arguments by reference so you can change them without returning or return a struct. You can only return a single value from a function.
we can only return one value. but in case you want to return multiple value you can use an array or define a object or a structure
int* arguments() {
int x[1,4,6]
return x;
};
void length(int i[]);
length(arguments());