This question already has an answer here:
Deducing array size in template function, pass-by-value vs pass-by-reference difference [duplicate]
(1 answer)
Closed last month.
In the following code:
template <typename T, size_t n>
constexpr size_t array_size(T(&) [n]) { return n; }
A reference (&) is used to successfully substitute the template. Removing the reference results in this error:
'template<class T, long unsigned int n> constexpr size_t array_size(T*)'
5 | constexpr size_t array_size(T [n]) { return n; }
note: template argument deduction/substitution failed:
note: couldn't deduce template parameter 'n'
When trying to call the function array_size with an array declared on the stack such as int test[10];.
Adding the reference seems to "force" the compiler to find the appropriate substitution. What extra information does the compiler get from the reference for it to work with the reference and fail without?
A weird quirk of C++ is that you can't actually pass arrays as parameters. You can only pass pointers or references to arrays, or pointers to data. If you attempt to pass an array to a function, then it actually just passes a pointer to the data.
void foo(int array[3]) {}
void foo(int* ptr) {} //fails to compile because `foo(int*)` already exists.
:(
Related
I have a homework in university. I need to change some elements' positions in an array inside an external function, but initialise then in the main function.
Here is the code:
template <int K>
void g(int (&X)[K][K]) {/*some code here*/}
int main() {
int T[8][8];
g(T);
// some more code...
return 0;
}
The question is why are parentheses are required for reference in this case?
When I try to write this parameter without them
template <int K>
void g(int &X[K][K]) {/*some code here*/}
I get an error "Unacceptable array of references" (error 2234). in the declaration of g.
The parentheses are needed to disambiguate between applying the reference "operator"1 on the array itself versus on the type of the element.
Note that reference types are not valid element type for an array, so T &identifier[length] is never valid. Pointers are valid element types, and T *identifier[length] is array of pointers while T (*identifier)[length] is pointer to an array and T *(&identifier)[length] is a reference to an array of pointers.
1 Technically, the grammar calls the token a ptr-operator, but it is neither an operator nor limited to a pointer declaration.
Why the compiler fails to infer template argument in the following code? How can I fix the code? I want add as low runtime overhead as possible.
#include <iostream>
using namespace std;
struct Test
{
template<int N>
Test(const char data[N]) :
data(data),
size(N)
{}
const char *data;
int size;
};
int main()
{
Test test("Foobar");
return 0;
}
I tried to make the snippet as small and readable as possible.
pos-reply UPDATE:
This explanation from Tales of C++ K-ballo might be useful:
Lvalue transformations, applied when an lvalue argument is used in context where an rvalue is expected. Those transformations are lvalue to rvalue conversion, array to pointer conversion, and function to pointer conversion. This is the type conversion applied to all function arguments when passed by value, and it is customary referred to as argument decay.
You need to accept the argument by reference:
Test(const char (&data)[N] )
Now N will be inferred.
In your case, the argument is accepted by value which causes the array to decay to pointer to the first element of the array when it gets passed to the constructor.
I am trying to use an integer as a template parameter for a class. Here is a sample of the code:
template< int array_qty >
class sample_class {
public:
std::array< std::string, array_qty > sample_array;
}
If I do so something like this, it works:
sample_class< 10 > sample_class_instance;
However, let's say that I do not know the value of array_qty (the template parameter) when compiling, and will only know it during run-time. In this case, I would essentially be passing an int variable as the template argument. For the sake of demonstration, the following code does not work:
int test_var = 2;
int another_test_var = 5;
int test_array_qty = test_var * another_test_var;
sample_class< test_array_qty > sample_class_instance;
I get the following error during compile time when trying the above:
the value of ‘test_array_qty’ is not usable in a constant expression
I've tried converting test_array_qty to a const while passing it as the template parameter, but that doesn't seem to do the trick either. Is there any way to do this, or am I misusing template parameters? Perhaps they need to be known at compile time?
The goal is NOT to solve this specific approach, but rather to find a way to set the length of the array to an int variable that can be stated when instantiating the class. If there is a way to do this via a template parameter, that would be ideal.
Please note that I have to use an array for this, and NOT a vector which I may end up as a suggestion. Additionally, array_qty will always be a value between 0 and 50 - in case that makes a difference.
This can be done in effect. But trust me when I say you are asking the wrong question. So what follows answers your question, even thought doing it is a bad idea almost always.
What you in effect can do is create 50 different programs, one for each of the 50 possible sizes, and then conditionally jump to the one you want.
template<int n>
struct prog {
void run() {
// ...
}
};
template<int n>
struct switcher {
void run(int v) {
if(v==n)
prog<n>::run();
else
switcher<n-1>::run(v);
}
};
template<>
struct switcher<-1> {
void run(int v){
}
};
Call switcher<50>::run( value ); and if value is 0 to 50, prog<value>::run() is invoked. Within prog::run the template parameter is a compile time value.
Horrid hack, and odds are you would be better off using another solution, but it is what you asked for.
Here is a C++14 table-based version:
template<size_t N>
using index_t = std::integral_constant<size_t, N>; // C++14
template<size_t M>
struct magic_switch_t {
template<class F, class...Args>
using R=std::result_of_t<F(index_t<0>, Args...)>;
template<class F, class...Args>
R<F, Args...> operator()(F&& f, size_t i, Args&&...args)const{
if (i >= M)
throw i; // make a better way to return an error
return invoke(std::make_index_sequence<M>{}, std::forward<F>(f), i, std::forward<Args>(args)...);
}
private:
template<size_t...Is, class F, class...Args>
R<F, Args...> invoke(std::index_sequence<Is...>, F&&f, size_t i, Args&&...args)const {
using pF=decltype(std::addressof(f));
using call_func = R<F, Args...>(*)(pF pf, Args&&...args);
static const call_func table[M]={
[](pF pf, Args&&...args)->R<F, Args...>{
return std::forward<F>(*pf)(index_t<Is>{}, std::forward<Args>(args)...);
}...
};
return table[i](std::addressof(f), std::forward<Args>(args)...);
}
};
magic_switch_t<N>{}( f, 3, blah1, blah2, etc ) will invoke f(index_t<3>{}, blah1, blah2, etc).
Some C++14 compilers will choke on the variardic pack expansion containing a lambda. It isn't essential, you can do a workaround, but the workaround is ugly.
The C++14 features are all optional: you can implement it all in C++11, but again, ugly.
The f passed basically should be a function object (either a lambda taking auto as the first argument, or a manual one). Passing a function name directly won't work well, because the above best works when the first argument becomes a compile-time value.
You can wrap a function template with a lambda or a function object to help.
For C++ 11, non-type template arguments are restricted to the following (§14.3.2/1):
A template-argument for a non-type, non-template template-parameter shall be one of:
for a non-type template-parameter of integral or enumeration type, a converted constant expression (5.19) of the type of the template-parameter; or
the name of a non-type template-parameter; or
a constant expression (5.19) that designates the address of an object with static storage duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as & id-expression, except that the & may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; or
a constant expression that evaluates to a null pointer value (4.10); or
a constant expression that evaluates to a null member pointer value (4.11); or
a pointer to member expressed as described in 5.3.1.
In C++ 98 and 03, the list is even more restricted. Bottom line: what you're trying to do simply isn't allowed.
Template arguments must be compile-time constants aka "constant expressions" or constexprs for short. So there is no way to do is using templates.
You could use a dynamic-sized array and store its size in an int.
Or simply use a vector. Be sure to initialize its size in the constructor by passing the desired size to the vector's constructor!
Sorry, this is not possible. The template argument must be a constant expression known at compile time.
I'm a little late, but here's my suggestion. I'm guessing the main problem with vectors for you is that they allocate a larger capacity than what you need in order to support dynamic growth. So, can't you write your own simple array class?
template <typename T>
class Array {
private:
T* data;
unsigned size;
public:
Array(unsigned size) {
data = new T[size];
this->size = size;
}
T& operator[](int i) {
return data[i];
}
T operator[](int i) const {
return data[i];
}
// Depending on your needs, maybe add copy constructor and assignment operator here.
...
unsigned size() {
return size;
}
~Array() {
delete [] data;
}
}
From what I know, I believe this should be just as fast as the STL array class. In addition, you can create Arrays with sizes unknown until run-time, the Array's memory is handled automatically when it is destroyed, and you don't have to instantiate a new class every time you create a new array with a different size (like you have to do for STL arrays).
I tried to find a solution for the problem of the question C++ template non-type parameter type deduction, which does not involve a template parameter to call f, but implicitly chooses the correct type for the template parameter.
Since constexpr should guarantee that a function only contains compile time constants, and is evaluated at compile time (at least thats what i think it does), i thought it might be the solution for this issue.
So i came up with this:
template <class T, T VALUE> void f() {}
//first i tried this:
template <class T> auto get_f(T t) -> decltype( &f<T,t> ) { return f<T,t>; }
//second try:
template <class T> constexpr void (&get_f( T t ))() { return f<T,t>; }
int main()
{
get_f(10)(); //gets correct f and calls it
}
first version generates following error:
error: use of parameter 't' outside function body
which is really confusing, since the usage of parameters in the decltype statement of a trailing return type should be ok?
second version generates following error:
error: invalid initialization of non-const reference of type 'void (&)()'
from an rvalue of type '<unresolved overloaded function type>'
which is kinda confusing, since i fully qualified f in get_f.
I would expect this kind of error messages if i did not have the constexpr. So do i have a false understanding of what constexpr does, or is the C++0x implementation of GCC flawed for this case ?
I am using GCC 4.6.2
Since constexpr should guarantee that a function only contains compile
time constants, and is evaluated at compile time (at least thats what
i think it does), i thought it might be the solution for this issue.
A constexpr function can be used in a constant expression context, but is not restricted to one. In this respect they are different from a metafunction and a regular function. Consider the problem of returning the successor of an integer:
// Regular function
int f(int i)
{ return i + 1; }
// Regular metafunction
template<int I>
struct g {
static constexpr auto value = I + 1;
};
// constexpr function
constexpr int h(int i)
{ return i + 1; }
// Then...
{
// runtime context: the metafunction can't be used
int i;
std::cin >> i;
f(i); // Okay
g<i>::value; // Invalid
h(i); // Okay
// compile time context: the regular function can't be used
char a[f(42)]; // Invalid
char b[g<42>::value]; // Okay
char c[h(42)]; // Okay
}
constexpr has other usages (e.g. constructors) but when it comes to constexpr functions this is the gist of it: some functions should be available in both runtime and constant contexts because some computations are available in both. It's possible to compute i + 1 whether i is a compile-time constant or is extracted from std::cin.
This means that inside the body of a constexpr function the parameters are not themselves constant expressions. So what you are attempting is not possible. Your function can't deal with
int i;
std::cin >> i;
get_f(i); // what's the return type?
and the violation happens here:
constexpr auto get_f(T t)
-> decltype( &f<T,t> ) // <-
Since t is not a constant expression according to the rules of the language (no matter what, even if you actually only pass constant expressions in), it can't appear as the second template parameter of f.
(And in the larger picture it means that no, you can't use argument deduction from function templates to conveniently pass a non-type parameter to a class template.)
Please consider this code:
#include <iostream>
template<typename T>
void f(T x) {
std::cout << sizeof(T) << '\n';
}
int main()
{
int array[27];
f(array);
f<decltype(array)>(array);
}
Editor's Note: the original code used typeof(array), however that is a GCC extension.
This will print
8 (or 4)
108
In the first case, the array obviously decays to a pointer and T becomes int*. In the second case, T is forced to int[27].
Is the order of decay/substitution implementation defined? Is there a more elegant way to force the type to int[27]? Besides using std::vector?
Use the reference type for the parameter
template<typename T> void f(const T& x)
{
std::cout << sizeof(T);
}
in which case the array type will not decay.
Similarly, you can also prevent decay in your original version of f if you explicitly specify the template agument T as a reference-to-array type
f<int (&)[27]>(array);
In your original code sample, forcing the argument T to have the array type (i.e. non-reference array type, by using typeof or by specifying the type explicitly), will not prevent array type decay. While T itself will stand for array type (as you observed), the parameter x will still be declared as a pointer and sizeof x will still evaluate to pointer size.
The behaviour of this code is explained by C++14 [temp.deduct.call]:
Deducing template arguments from a function call
Template argument deduction is done by comparing each function template parameter type (call it P) with the type of the corresponding argument of the call (call it A) as described below
and then below:
If P is not a reference type:
If A is an array type, the pointer type produced by the array-to-pointer standard conversion (4.2) is used in place of A for type deduction;
For the call f(array);, we have A = int[27]. A is an array type. So the deduced type T is int *, according to this last bullet point.
We can see from the qualifier "If P is not a reference type" that this behaviour could perhaps be avoided by making P a reference type. For the code:
template<typename T, size_t N>
void f(T (&x)[N])
the symbol P means T(&)[N], which is a reference type; and it turns out that there are no conversions applied here. T is deduced to int, with the type of x being int(&)[N].
Note that this only applies to function templates where the type is deduced from the argument. The behaviour is covered by separate parts of the specification for explicitly-provided function template parameters, and class templates.
You can also use templates like the following:
template <typename T, std::size_t N>
inline std::size_t number_of_elements(T (&ary)[N]) {
return N;
}
This little trick will cause compile errors if the function is used on a non-array type.
Depending on your use case, you can work around that using references:
template<typename T>
void f(const T& x) {
std::cout << sizeof(T);
}
char a[27];
f(a);
That prints 27, as desired.