Unable to instantiate generic function in a loop - c++

I have some generic function, which looks similar to
template<int P>
struct foo {
static const int value = ...;
};
Now, I want to call this generic function in a loop. Like so:
for (int i = 0; i < 100; ++i)
{
auto bar = foo<i>::value;
}
But I get a lot of error messages. Like
the value of 'i' is not used in a constant expression
int i is not constant
I tried to fix it with:
foo<(const int)i>::value;
But to no avail. So, what is wrong with that and how can I make it work?

You cannot do it this way.
for (int i = 0; i < 100; ++i)
{
auto bar = foo<i>::value;
}
i needs to me a constant expression, so that the compiler can generate the code for it when it compiles your program.
Here's an exhaustive explanation of what constant expressions are:
http://en.cppreference.com/w/cpp/language/constant_expression
Here's a segment from the site:
int n = 1;
std::array<int, n> a1; // error: n is not a constant expression
const int cn = 2;
std::array<int, cn> a2; // OK: cn is a constant expression
So to make it happen compile time, you need to make your loop into a template recursion using variadic templates.
Maybe you can understand what you need to do better if you read this example:
// Example program
#include <iostream>
#include <string>
template<int P>
struct foo
{
static const int value = P;
};
template <int TIndex>
int call()
{
return foo<TIndex>::value;
}
template <int TIndex, int TIndex2, int ...Rest>
int call ()
{
return call<TIndex>() + call<TIndex2, Rest...>();
}
int main()
{
std::cout << "Test: " << call<1, 2>() << "\n"; // prints "Test: 3"
}
Nicky C posted a link to another question. It has a good answer and I don't feel right in copying it here. Take a look at my working example above and then look at the answer here:
https://stackoverflow.com/a/11081785/493298
You should be able to make it work. It's a bit of a syntax hell, but you can manage it, I'm sure.

Related

Check Equality of Types

I have a struct and template class, within which there is a function that should check if T is equal to the struct and if so, do something.
The struct:
struct mystruct
{
int x;
int y;
int z;
};
the template class:
template <typename T>
class myclass
{
public:
void myfunc()
{
// this condition is ignored..
if(std::is_same<T,mystruct>::value==0)
{
cout << "T is not mystruct type" << '\n';
}
else
{
T ms;
ms.x = 5;
ms.y = 4;
ms.z = 3;
}
}
};
in main function, if T == mystruct everything goes through fine:
int main()
{
// no issues
myclass<mystruct> x;
x.myfunc();
}
but if T != mystruct:
int main()
{
//tries to unsuccessfuly convert int to mystruct
myclass<int> x;
x.myfunc();
}
execution fails with the below error:
error: request for member 'x' in 'ms', which is of non-class type 'int'
ms.x = 5;
does anyone have an idea why the if-else statement not working as expected?
Thanks!
Even if the if condition evaluates to false, for a particular template instantiation, the entire template still must consist of valid C++ code.
If the template's parameter is int, for example, then the else part of the if statement becomes equivalent to:
else
{
int ms;
ms.x = 5;
ms.y = 4;
ms.z = 3;
}
It should be obvious why this won't compile. Because the entire template becomes, equivalent to:
if (true)
{
cout << "T is not mystruct type" << '\n';
}
else
{
int ms;
ms.x = 5;
ms.y = 4;
ms.z = 3;
}
Even though else never gets executed, it stlil must be valid C++ code. Templates are no different.
C++17 introduced if constexpr which requires that the evaluated if expression is constant, and only the appropriate part of the if statement ends up being compiled, with the rest being effectively discarded. So, with C++17, you should be able to change the if statement to if constexpr, and get the expected results.

How to use template data type inside main function in C++?

#include <iostream>
using namespace std;
template <class U>
U add (U a, U b)
{
U c = 0 ;
c = a + b;
return c;
}
int main()
{
int first = 2;
int second = 2;
U result = 0;
result = add(first, second);
cout << result << endl;
return 0;
}
I want to declare the data type of result variable using the template data type so that my addition program is generic but the compiler is giving me this error "result was not declared in this scope."
What you are trying to do is not possible. You can only use U within your add function.
However, you can do this instead
auto result = add(first, second);
Or
decltype(auto) result = add(first, second);
In your case both will do the same. However, they are quite different. To make it short, decltype(auto) will always get you the exact type returned by add, while auto may not.
Quick example:
const int& test()
{
static int c = 0;
return c;
}
// result type: int
auto result = test();
// result type: const int&
decltype(auto) result = test();
If you want to know more about auto, Scott Meyers explains it perfectly:
CppCon 2014: Scott Meyers "Type Deduction and Why You Care"
An alternative to José's excellent proposal, which would allow you to split the declaration and "initialisation" (which would then only be an assignment, as in your question), is:
decltype(add(first, second)) result = 0;
result = add(first, second);
But, obviously, yuck.

When non-const members can be used in constexpr member functions?

I encountered a situation I don't understand. Would somebody be so nice to explain why first code compiles correctly while second gives an error:
error: the value of 'TestClass::z' is not usable in a constant expression
static constexpr int sum() {return x+y+z;}
----------------------------------------------------^
note: 'int TestClass::z' is not const
static int z;"
Working code:
#include <iostream>
using namespace std;
class TestClass
{
public:
constexpr int sum() {return x+y+z;}
private:
static constexpr int x = 2;
static const int y = 3;
int z = 5;
};
int main()
{
TestClass tc;
cout << tc.sum() << endl;
return 0;
}
But when I try to make TestClass::sum() static I get aforementioned error:
#include <iostream>
using namespace std;
class TestClass
{
public:
static constexpr int sum() {return x+y+z;}
private:
static constexpr int x = 2;
static const int y = 3;
static int z;
};
int TestClass::z = 5;
int main()
{
TestClass tc;
cout << tc.sum() << endl;
return 0;
}
P.S. I'm using mingw32-g++ 4.8.1
In the first case, the result depends only on the function's arguments, including the implicit this used to access z. This doesn't disqualify it from being constexpr - if all the arguments are constant expressions, then so is the result.
In your example, it isn't a constant expression (since tc isn't), but that doesn't matter since it's not being used in a context that requires one. Here's an example showing its use in a constant expression:
constexpr TestClass tc;
array<int, tc.sum()> a;
cout << a.size() << endl;
In the second case, the result also depends on a static variable, whose value could change during the program. This does disqualify it - even if all the arguments are constant expressions, z isn't, and so the result of a function call can never be a constant expression.

Static class member

What's wrong with the code below? Latest version of g++ and clang both give error. I am sure I am missing something basic here.
#include <iostream>
struct Z
{
static const int mysize = 10;
};
Z f2();
int main()
{
std::cout << f2()::mysize << std::endl;
}
The motivation here is to be able to find out the size of an array using templates using code such as below. I know there are many ways, but just stumbled upon this idea.
template<int N> struct S
{
enum { mysize = N };
};
template<class T, int N> S<N> f(T (&)[N]);
int main()
{
char buf[10];
std::cout << f(buf)::mysize << std::endl;
}
f2() returns a value, not a type. You'd need to use the . operator on the return value instead of ::
The :: operator requires a type to be named on the lefthand side, while . allows for a value to be named. Your expression f2() does not name a type so it cannot be used in conjunction with ::.
As a side note, with a little more detail in the question we might be able to solve your real problem.
Your program contains two mistakes:
You are using the :: operator to access the member of an object. Use operator . ("dot") instead;
You declare function f2() and invoke it without defining it (this will give you a linker error).
Also, since static member variables are shared among all instances of a class (Z in this case), you do not need an object to access it;
Here is how you could fix your program:
#include <iostream>
struct Z
{
static const int mysize = 10;
};
Z f2() { return Z(); }
int main()
{
// Don't need an object to access a static variable...
std::cout << Z::mysize << std::endl;
// ...but if you really want to, do it this way...
std::cout << f2().mysize << std::endl;
}
Why don't you use this way to find out the size of array by templates:
#include <iostream>
template<int N> struct S
{
enum { mysize = N };
};
template<class T, int N> int f1(T (&)[N])
{
return N;
}
int main()
{
char buf[10];
std::cout << f1(buf) << std::endl;
}
And this one is closer to your variant:
template<class T, int N> S<N> f(T (&)[N])
{
S<N> foo;
return foo;
}
int main()
{
char buf[10];
std::cout << f(buf).mysize << std::endl;
}
Anyway, you will need to return an object from f and access it's member by ., not by ::.
But it's more probable that second variant will be slower, because first variant is fully compile-time, but in the second variant compiler may miss the optimization and don't optimize out the run-time creation of foo.
I think you need to add const int Z::mysize; after class declaration.

Template in C++, why have to use enum

I have a quick question about item 48 in Scott Meyers' "Effective C++".
I just don't understand the code copied from the book below,
#include <iostream>
using namespace std;
template <unsigned n>
struct Factorial
{
enum { value=n*Factorial<n-1>::value };
};
template <>
struct Factorial<0>
{
enum { value=1};
};
int main()
{
cout<<Factorial<5>::value<<endl;
cout<<Factorial<10>::value<<endl;
}
Why do I have to use enum in template programming?
Is there an alternative way to do this?
Thanks for the help in advance.
You could use static const int also:
template <unsigned n>
struct Factorial
{
static const int value= n * Factorial<n-1>::value;
};
template <>
struct Factorial<0>
{
static const int value= 1;
};
This should be fine also. The result is same in both cases.
Or you could use existing class template, such as std::integral_constant (in C++11 only) as:
template <unsigned n>
struct Factorial : std::integral_constant<int,n * Factorial<n-1>::value> {};
template <>
struct Factorial<0> : std::integral_constant<int,1> {};
I see that the other answers cover the alternative approaches well, but no one's explained why the enum (or static const int) is required.
First, consider the following non-template equivalent:
#include <iostream>
int Factorial(int n)
{
if (n == 0)
return 1;
else
return n * Factorial(n-1);
}
int main()
{
std::cout << Factorial(5) << std::endl;
std::cout << Factorial(10) << std::endl;
}
You should be able to understand it easily. However, it's disadvantage is that the value of the factorial will be computed at run-time, i.e. after running your program the compiler will execute the recursive function calls and calculations.
The idea of template approach is to perform the same calculations at compile-time, and place the result in the resulting executable. In other words, the example you presented resolves to something alike:
int main()
{
std::cout << 120 << std::endl;
std::cout << 3628800 << std::endl;
}
But in order to achieve that, you have to 'trick' the compiler into performing the computations. And in order to do that, you need to let it store the result somewhere.
The enum is there exactly in order to do that. I will try to explain that by pointing out what would not work there.
If you tried to use a regular int, it would not work because a non-static member like int is meaningful only in a instantiated object. And you can't assign a value to it like this but instead do that in a constructor. A plain int won't work.
You need something that would be accessible on an uninstantiated class instead. You could try static int but it still doesn't work. clang would give you a pretty straightforward description of the problem:
c.cxx:6:14: error: non-const static data member must be initialized out of line
static int value=n*Factorial<n-1>::value ;
^ ~~~~~~~~~~~~~~~~~~~~~~~
If you actually put those definitions out-of-line, the code will compile but it will result in two 0s. That is because this form delays the computation of values to the initialization of program, and it does not guarantee the correct order. It is likely that a Factorial<n-1>::values was obtained before being computed, and thus 0 was returned. Additionally, it is still not what we actually want.
Finally, if you put static const int there, it will work as expected. That's because static const has to be computed at the compile time, and that's exactly what we want. Let's type the code again:
#include <iostream>
template <unsigned n>
struct Factorial
{
static const int value=n*Factorial<n-1>::value ;
};
template <>
struct Factorial<0>
{
static const int value=1;
};
int main()
{
std::cout << Factorial<5>::value << std::endl;
std::cout << Factorial<10>::value << std::endl;
}
First you instantiate Factorial<5>; static const int forces the compiler has to compute its value at compiler time. Effectively, it instantiates the type Factorial<4> when it has to compute another value. And this goes one until it hit Factorial<0> where the value can be computed without further instantiations.
So, that was the alternate way and the explanation. I hope it was at least a bit helpful in understanding the code.
You can think of that kind of templates as a replacement of the recursive function I posted at the beginning. You just replace:
return x; with static const int value = ...,
f(x-1) with t<x-1>::value,
and if (n == 0) with the specialization struct Factorial<0>.
And for the enum itself, as it was already pointed out, it was used in the example to enforce the same behavior as static const int. It is like that because all the enum values need to be known at compile-time, so effectively every requested value has to be computed at compile-time.
To be more specific, the "enum hack" exists because the more correct way of doing it with static const int was not supported by many compilers of the time. It's redundant in modern compilers.
You can use static const int as Nawaz says. I guess the reason Scott Myers uses an enum is that compiler support for in-class initialization of static const integers was a bit limited when he wrote the book. So an enum was a safer option.
You can use an int instead of static const it for this as follows:
template<int n>
struct Factorial
{
int val{ n*Factorial<n - 1>().val };
};
template<>
struct Factorial<0>
{
int val{1};
};
int main()
{
cout << "Factorial 5: " << Factorial<5>().val << endl;
}
You can also use function template instead of struct/class template:
template<int n>
int fact()
{
return n*fact<n - 1>();
}
template <>
int fact<0>()
{
return 1;
}
int main()
{
cout << "Fact 5: " << fact<5>() << endl;
}