I have remembered now that I saw something like this in C:
void foo(int bar; char baz[bar]) { ... }
I don't remember its name or the valid syntax and I wonder if it's available in C++ too?
No, that's not possible according to the standard, since you are dynamically passing the size of the array to the function, unless there is some special compiler extension that I'm missing.
What you can do is to specify it as a template argument and let the deduction do its work, eg:
template<size_t size>
void foo (char (&a)[size])
{
for (size_t i = 0; i < size; ++i)
cout << a[i] << endl;
}
int main()
{
char a[] = {'a','b','c','d','e'};
foo(a);
return 0;
}
Or, since you are working with C++, use an std::array or std::vector and iterators.
For starters, char baz[10] when used as a parameter declares a pointer, not an array, so 10 is completely ignored. This is called array decay to pointer and it's an unfortunate inheritance from C.
Considering you weren't asking strictly about array size, and expanding your question to any use of a previous parameter, the case would be default arguments. E.g.
void foo(int a, int b = a);
And here the answer is again no, it is not valid.
See this answer: https://stackoverflow.com/a/1880877/2805305 for standard justification.
Actually, there is some "Forward use of function parameter" in C++, but not what you are talking about.
Since C++11, you can do stuff like this to deduce type of parameters (or return type) using previous parameter:
template <typename T>
auto get (T const& t, size_t i) -> decltype(t[i]) { }
Or:
template <typename T>
void set (T &t, size_t i, decltype(t[i]) const& v) { }
Maybe I am completely off, but since you did not remember exactly what you saw, I thought this might have been stuff like this.
Related
I've got code that can be simplified to
std::variant<float, int> v[2] = foo();
int a = std::get<decltype(a)>(v[0]);
float b = std::get<decltype(b)>(v[1]);
Obviously this can go throw if foo() returns the wrong variants, but that's not my problem here. (The real code has a catch). My problem is that the decltype(a) violates the Don't Repeat Yourself principle.
Is there a cleaner way to initialize a and b, and still throw if the types do not match expectations? In particular, I don't want a static_cast<int>(std::get<float>(v)) if the variant contains a float while I'm trying to initialize an int.
You could wrap your call to get in a template that implicitly converts to the target type.
template<typename... Ts>
struct variant_unwrapper {
std::variant<Ts...> & var;
template <typename T>
operator T() { return std::get<T>(var); }
};
See it on coliru
IMO it would be nice to allow template deduction to take over, so providing a helper function should do the job:
template<typename T, typename...VariantParams>
void get_from(const std::variant<VariantParams...>& v, T& value)
{
value = ::std::get<T>(v);
}
int a;
get_from(v[0], a);
As #paulo says in the comments, seems like the DRY solution is to use auto for the declaration, changing:
int a = std::get<decltype(a)>(v[0]);
to:
auto a = std::get<int>(v[0]);
You only name the type (int) and the variable (a) once each. Doesn't work if you separate declaration and initialization, so you'd still need:
int a;
...
a = std::get<decltype(a)>(v[0]);
in that case, but if you write all your C++ code deferring declarations until the point of definition, it's not needed often.
So, let's say I'm writing a function to set an array using a user-supplied callback per item. (I'm not, but let's suppose I am, for the purposes of a minimal example)
The cleanest way I can find to do this is the following:
#include <functional>
template<typename T, typename Y>
void PopulateArray(std::function<int(Y*)> callback, T &pArray)
{
for (int i = 0; i < sizeof(pArray); ++i)
int x = callback(&pArray[i]);
}
int main()
{
uint64_t myArray[5];
uint64_t myUint = 42;
PopulateArray( (std::function<int(uint64_t*)>) [=](auto x) {*x = myUint; return 0; },
myArray);
}
I have two issues with the code above.
1) For T to be an array type, there seems to be no way to modify the parameter. (I can't say I want an array of type T, meaning I have to declare Y separately, even though they are both related to uint64_t.) I would prefer to declare a single T, with one parameter being a pointer to T and the other being an array of T.
2) The client code (in main), is forced to cast the lambda. Changing auto x to an explicit type doesn't seem to help matters.
Is there a resolution to #1 or #2 that might make the code more succinct or readable?
Code will need to compile with gcc, clang, and VS. I think C++11 is the newest standard I can use, although I'd be interested in C++14 solutions, as that would be a matter of upgrading our clang build process. I'm not interested in solutions that involve switching myArray to std::array std::vector, etc..
Drop the requirement for std::function:
// You could consider using an array type for the parameter:
// template <typename Callback, typename T, std::size_t N>
// void PopulateArray(Callback callback, T (&pArray)[N])
template<typename Callback, typename T>
void PopulateArray(Callback callback, T& pArray)
{
// sizeof(pArray) as in the question is almost certainly not what you
// want. It returns the size *in bytes*, not the length of the array.
// Thus, if you specified this to take an array reference,
// `for (std::size_t i = 0; i < N; ++i)` would be correct.
// However, as Barry mentioned in the comments, a range-based for loop
// is the best solution.
for (T& element : pArray)
callback(&element);
}
int main()
{
std::uint64_t myArray[5];
PopulateArray([](auto x) {*x = 42; return 0; },
myArray);
}
std::function is an expensive type. It uses virtual function calls (or techniques that are very similar) and has the potential to allocate memory. If you are not storing the function and especially if the function is already a template, just take an arbitrary callback as your parameter. If you really want to constrain the callback's type, use a function_ref type (not yet standardized), or check that callback(your, args) is valid:
template<typename Callback, typename T>
auto PopulateArray(Callback callback, T& pArray)
-> decltype(callback(*std::begin(pArray)), void())
{
for (T& element : pArray)
callback(&element);
}
Also, in this specific case, you can use an algorithm:
int main()
{
uint64_t myArray[5];
uint64_t myUint = 42;
// If it's all the same value:
std::fill(std::begin(myArray), std::end(myArray), myUint);
// To call a function to populate the array:
std::generate(std::begin(myArray), std::end(myArray), [myUint] {
return myUint;
});
// Or possibly:
std::for_each(std::begin(myArray), std::end(myArray),
[myUint](uint64_t& element) {
element = myUint;
});
}
I'm trying to pass a pointer (char*) to a generic function i wrote. But i get an error " Overloaded foo ambiguous in this context ". Why does this happen?
template <class T>
T foo(T a, T b)
{
return a+b;
}
int main()
{
char *c="Hello",*d="world";
foo<char*>(c,d);
return 0;
}
It have no reason to add two pointers, it result in a non-sensical pointer. Imagine e.g. that the first text is at address 0x7fffff00, and the second one is in 0x80000100. Then after an addition on 32-bit machine you going to get… 0. Zero. Null pointer!
Perhaps you wanted to use string's instead, like:
#include <string>
template <class T>
T foo(T a, T b)
{
return a+b;
}
int main()
{
std::string c="Hello", d="world";
foo(c,d);
return 0;
}
Also note: in many cases (like this one) compiler can infer template type for you, so no reason to write it explicitly like foo<std::string>(c,d).
I thought that a function template parameters are declared only by class identifiers, for example:
template<class T1, class T2> void fun(T1 a, T2 b){}
but I found other example where fundamental type can be used as a parameter:
template<int R, int C>
void fun(double (&arr)[R][C])
{
for(int i = 0; i < R; ++i)
{
for(int j = 0; j < C; ++j)
{
cout<<arr[i][j]<<" ";
}
cout<<endl;
}
}
A function execution looks like this:
fun(myArray);
How that mechanism works ? Could you give me another examples where a fundamental type can be used as a function template parameter ?
In my travels, I have found three primary uses for template parameters as fundamental types:
One is building a function template that takes a C-style array. That's what you've posted here, but more commonly I have seen this applies to char arrays, as with:
template <size_t N, typename Char>
string MakeString (Char const (&chars)[N])
{
return string (chars, N);
}
int main()
{
string hi = MakeString ("Hello");
cout << hi;
}
Another use is building a kind of cheap attribute system using template metaprogramming. For example, suppose you have a bunch of classes meant to represent messages in some wire protocol, and for testing purposes you want to compare the actual size of the message class with what the specifications say the size should be.
enum MsgType
{
MsgType_Foo,
MsgType_Bar
};
class FooMsg
{
uint32_t mField;
char mName [9];
};
class BarMsg
{
char mPrice [8];
static const size_t SpecSize = 8;
};
template <MsgType MT> size_t SpecSize();
template <> size_t SpecSize <MsgType_Foo> ()
{
return 13;
}
template <> size_t SpecSize <MsgType_Bar> ()
{
return 9;
}
int main()
{
assert (SpecSize <MsgType_Foo> () == sizeof (FooMsg));
assert (SpecSize <MsgType_Bar> () == sizeof (BarMsg));
}
Note that if you run this program the assertions will fail unless you do something platform-specific (like #pragma pack (push, 1)) to fix the packing. This is one of the things the tests are intended to catch!
Finally, another common use is more specific but the technique can be applied to your own code. In Boost.Tuple, and now C++11, the tuple class uses a template function get<size_t> as a means to access the elements. Here is an example taken from en.cppreference.com:
#include <iostream>
#include <string>
#include <tuple>
int main()
{
auto t = std::make_tuple(1, "Foo", 3.14);
// index-based access
std::cout << "(" << std::get<0>(t) << ", " << std::get<1>(t)
<< ", " << std::get<2>(t) << ")\n";
}
I guess you could think of this as a specialization of both of previous examples. It's yet more template metaprogramming trickery that turns out to be quite useful in certain situations.
Despite they syntax allowing1 class for template parameters, like: template <class T>, there was never any intent that they be limited to user-defined types.
In other words, you can always pass a fundamental type as a template parameter unless the user has done something in the code inside the template to prevent it, such as with a static_assert or code inside the template that invokes a member function of the passed type.
For non-type template parameters, you're allowed to specify essentially any type. The template can be instantiated with a value that is of that type, or can be converted to that type.
1. You can use typename if you prefer -- some people prefer to, since it does a better job of conveying the idea that the name of any type is allowed.
It seems like you might be confused by the fact that templates often look like the following:
template <class T> void Bar( T param );
There is a synonym for class in this context that is more descriptive: typename. This tells you that any typename can be used as a template parameter, including primitive types or types that are generated from a template. So instead of writing the above you can write:
template <typename T> void Bar( T param );
In addition to types you can pass some instances of types to a template as you demonstrated. This is commonly done to set an array size in a class template, but has many other uses. As Praetorian mentioned in the comments, you can find more information by searching for non-type template arguments.
I'm looking for the rules involving passing C++ templates functions as arguments.
This is supported by C++ as shown by an example here:
void add1(int &v) { v += 1 }
void add2(int &v) { v += 2 }
template <void (*T)(int &)>
void doOperation()
{
int temp = 0;
T(temp);
std::cout << "Result is " << temp << std::endl;
}
int main()
{
doOperation<add1>();
doOperation<add2>();
}
Learning about this technique is difficult, however. Googling for "function as a template argument" doesn't lead to much. And the classic C++ Templates The Complete Guide surprisingly also doesn't discuss it (at least not from my search).
The questions I have are whether this is valid C++ (or just some widely supported extension).
Also, is there a way to allow a functor with the same signature to be used interchangeably with explicit functions during this kind of template invocation?
The following does not work in the above program, at least in Visual C++, because the syntax is obviously wrong. It'd be nice to be able to switch out a function for a functor and vice versa, similar to the way you can pass a function pointer or functor to the std::sort algorithm if you want to define a custom comparison operation.
struct add3 {
void operator() (int &v) {v += 3;}
};
...
doOperation<add3>();
Pointers to a web link or two, or a page in the C++ Templates book would be appreciated!
Yes, it is valid.
As for making it work with functors as well, the usual solution is something like this instead:
template <typename F>
void doOperation(F f)
{
int temp = 0;
f(temp);
std::cout << "Result is " << temp << std::endl;
}
which can now be called as either:
doOperation(add2);
doOperation(add3());
See it live
The problem with this is that if it makes it tricky for the compiler to inline the call to add2, since all the compiler knows is that a function pointer type void (*)(int &) is being passed to doOperation. (But add3, being a functor, can be inlined easily. Here, the compiler knows that an object of type add3 is passed to the function, which means that the function to call is add3::operator(), and not just some unknown function pointer.)
Template parameters can be either parameterized by type (typename T) or by value (int X).
The "traditional" C++ way of templating a piece of code is to use a functor - that is, the code is in an object, and the object thus gives the code unique type.
When working with traditional functions, this technique doesn't work well, because a change in type doesn't indicate a specific function - rather it specifies only the signature of many possible functions. So:
template<typename OP>
int do_op(int a, int b, OP op)
{
return op(a,b);
}
int add(int a, int b) { return a + b; }
...
int c = do_op(4,5,add);
Isn't equivalent to the functor case. In this example, do_op is instantiated for all function pointers whose signature is int X (int, int). The compiler would have to be pretty aggressive to fully inline this case. (I wouldn't rule it out though, as compiler optimization has gotten pretty advanced.)
One way to tell that this code doesn't quite do what we want is:
int (* func_ptr)(int, int) = add;
int c = do_op(4,5,func_ptr);
is still legal, and clearly this is not getting inlined. To get full inlining, we need to template by value, so the function is fully available in the template.
typedef int(*binary_int_op)(int, int); // signature for all valid template params
template<binary_int_op op>
int do_op(int a, int b)
{
return op(a,b);
}
int add(int a, int b) { return a + b; }
...
int c = do_op<add>(4,5);
In this case, each instantiated version of do_op is instantiated with a specific function already available. Thus we expect the code for do_op to look a lot like "return a + b". (Lisp programmers, stop your smirking!)
We can also confirm that this is closer to what we want because this:
int (* func_ptr)(int,int) = add;
int c = do_op<func_ptr>(4,5);
will fail to compile. GCC says: "error: 'func_ptr' cannot appear in a constant-expression. In other words, I can't fully expand do_op because you haven't given me enough info at compiler time to know what our op is.
So if the second example is really fully inlining our op, and the first is not, what good is the template? What is it doing? The answer is: type coercion. This riff on the first example will work:
template<typename OP>
int do_op(int a, int b, OP op) { return op(a,b); }
float fadd(float a, float b) { return a+b; }
...
int c = do_op(4,5,fadd);
That example will work! (I am not suggesting it is good C++ but...) What has happened is do_op has been templated around the signatures of the various functions, and each separate instantiation will write different type coercion code. So the instantiated code for do_op with fadd looks something like:
convert a and b from int to float.
call the function ptr op with float a and float b.
convert the result back to int and return it.
By comparison, our by-value case requires an exact match on the function arguments.
Function pointers can be passed as template parameters, and this is part of standard C++
. However in the template they are declared and used as functions rather than pointer-to-function. At template instantiation one passes the address of the function rather than just the name.
For example:
int i;
void add1(int& i) { i += 1; }
template<void op(int&)>
void do_op_fn_ptr_tpl(int& i) { op(i); }
i = 0;
do_op_fn_ptr_tpl<&add1>(i);
If you want to pass a functor type as a template argument:
struct add2_t {
void operator()(int& i) { i += 2; }
};
template<typename op>
void do_op_fntr_tpl(int& i) {
op o;
o(i);
}
i = 0;
do_op_fntr_tpl<add2_t>(i);
Several answers pass a functor instance as an argument:
template<typename op>
void do_op_fntr_arg(int& i, op o) { o(i); }
i = 0;
add2_t add2;
// This has the advantage of looking identical whether
// you pass a functor or a free function:
do_op_fntr_arg(i, add1);
do_op_fntr_arg(i, add2);
The closest you can get to this uniform appearance with a template argument is to define do_op twice- once with a non-type parameter and once with a type parameter.
// non-type (function pointer) template parameter
template<void op(int&)>
void do_op(int& i) { op(i); }
// type (functor class) template parameter
template<typename op>
void do_op(int& i) {
op o;
o(i);
}
i = 0;
do_op<&add1>(i); // still need address-of operator in the function pointer case.
do_op<add2_t>(i);
Honestly, I really expected this not to compile, but it worked for me with gcc-4.8 and Visual Studio 2013.
In your template
template <void (*T)(int &)>
void doOperation()
The parameter T is a non-type template parameter. This means that the behaviour of the template function changes with the value of the parameter (which must be fixed at compile time, which function pointer constants are).
If you want somthing that works with both function objects and function parameters you need a typed template. When you do this, though, you also need to provide an object instance (either function object instance or a function pointer) to the function at run time.
template <class T>
void doOperation(T t)
{
int temp=0;
t(temp);
std::cout << "Result is " << temp << std::endl;
}
There are some minor performance considerations. This new version may be less efficient with function pointer arguments as the particular function pointer is only derefenced and called at run time whereas your function pointer template can be optimized (possibly the function call inlined) based on the particular function pointer used. Function objects can often be very efficiently expanded with the typed template, though as the particular operator() is completely determined by the type of the function object.
The reason your functor example does not work is that you need an instance to invoke the operator().
Came here with the additional requirement, that also parameter/return types should vary.
Following Ben Supnik this would be for some type T
typedef T(*binary_T_op)(T, T);
instead of
typedef int(*binary_int_op)(int, int);
The solution here is to put the function type definition and the function template into a surrounding struct template.
template <typename T> struct BinOp
{
typedef T(*binary_T_op )(T, T); // signature for all valid template params
template<binary_T_op op>
T do_op(T a, T b)
{
return op(a,b);
}
};
double mulDouble(double a, double b)
{
return a * b;
}
BinOp<double> doubleBinOp;
double res = doubleBinOp.do_op<&mulDouble>(4, 5);
Alternatively BinOp could be a class with static method template do_op(...), then called as
double res = BinOp<double>::do_op<&mulDouble>(4, 5);
EDIT
Inspired by comment from 0x2207, here is a functor taking any function with two parameters and convertible values.
struct BinOp
{
template <typename R, typename S, typename T, typename U, typename V> R operator()(R (*binaryOp )(S, T), U u, V v)
{
return binaryOp(u,v);
}
};
double subD(double a, int b)
{
return a-b;
}
int subI(double a, int b)
{
return (int)(a-b);
}
int main()
{
double resD = BinOp()(&subD, 4.03, 3);
int resI = BinOp()(&subI, 4.03, 3);
std::cout << resD << std::endl;
std::cout << resI << std::endl;
return 0;
}
correctly evaluates to double 1.03 and int 1
Edit: Passing the operator as a reference doesnt work. For simplicity, understand it as a function pointer. You just send the pointer, not a reference.
I think you are trying to write something like this.
struct Square
{
double operator()(double number) { return number * number; }
};
template <class Function>
double integrate(Function f, double a, double b, unsigned int intervals)
{
double delta = (b - a) / intervals, sum = 0.0;
while(a < b)
{
sum += f(a) * delta;
a += delta;
}
return sum;
}
.
.
std::cout << "interval : " << i << tab << tab << "intgeration = "
<< integrate(Square(), 0.0, 1.0, 10) << std::endl;