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;
}
Related
I am trying to design a class which all its data is constant and know at compile time. I could just create this by manually typing it all but I want to use a template so that I don't have to rewrite almost the same code many times.
I was thinking templates are the way to do this e.g
template<class T> class A { ... }
A<float>
A<MyObject>
A<int>
But then I wasn't sure how I could get the constant data that I know into this object. I could do it at run-time with a member function which does a switch statement on the type or something similar but I ideally want it to effectively be a dumb data holder for me to use.
So in the case of A<float> I would have this:
// member function
int getSize() {
return 4;
}
Instead of (pseudo code)
// member function
int getSize() {
if (type == float) {
return 4;
} else if ...
}
I'm wondering if there is a known way to do this? I don't have any experience with constexpr, could that be the key to this?
edit: To clarify: I want member functions which always return the same result based on the templated type/class. For example, A would always return 4 from getSize() and 1 from getSomethingElse() and 6.2 from getAnotherThing(). Where as A would return 8 from getSize() and 2 from getSomethingElse() and 8.4 from getAnotherThing().
You can have this template
template <int size_, int foo_, int bar_>
struct MyConstData {
static const int size = size_; // etc
};
Then specialize your template:
template <class T> class A;
template <> class A<float> : MyConstData<13,42,-1> {};
template <> class A<double> : MyConstData<0,0,42> {};
You can specialize particular functions within a class, and given your description of things, I suspect that's what you want. Here is an example of how this works:
#include <iostream>
#include <string>
template <class T>
class A {
public:
int MyConstantFunction() const { // Default implementation
return 0;
}
};
template <>
int A<int>::MyConstantFunction() const
{
return 3;
}
template <>
int A<float>::MyConstantFunction() const
{
return 5; // If you examine the world, you'll find that 5's are everywhere.
}
template <>
int A<double>::MyConstantFunction() const
{
return -5;
}
int main(int, char *[])
{
using ::std::cout;
A<int> aint;
A<float> afloat;
A<long> along;
cout << "aint.MyConstantFunction() == " << aint.MyConstantFunction() << '\n';
cout << "afloat.MyConstantFunction() == "
<< afloat.MyConstantFunction() << '\n';
cout << "along.MyConstantFunction() == "
<< along.MyConstantFunction() << '\n';
return 0;
}
Notice how along just used the default implementation from the class declaration. And this highlights a danger here. If the translation unit using your specialization for a given type hasn't seen that specialization, it won't use it, and that may cause all kinds of interesting problems. Make sure this happens.
The other option is to not provide a default implementation at all, and so you get an instantiation error.
My gut feeling is that you are doing something that is pointless and a poor design. But, since I don't know the full context I can't say that for sure. If you insist on doing this, here's how.
If you want to implement different things depending on the type, you could try this:
template <class T>
class Foo {
T data;
string toString() {
return myGeneralToString(data);
}
};
template <>
class Foo<string> {
string data;
string toString() {
return "Already a string: " + data;
}
};
If you just want templated constants, I'd try this:
template <int a, int b>
class Calc {
public:
static constexpr int SUM = a + b;
};
int main()
{
std::cout << Calc<3, 5>::SUM << std::endl;
return 0;
}
Edit: as pointed out by Omnifarious C++14 has templated constants without templating the class itself. So you could simplify the example to:
class Calc {
public:
template <int a, int b>
static constexpr int SUM = a + b;
};
int main()
{
std::cout << Calc::SUM<3, 5> << std::endl;
return 0;
}
I know we can define templates using constants. For instance:
template<int N>
struct FixedArray {
double values[N];
int size() { return N; } // Could be static
};
int main(int, char**) {
FixedArray<10> arr;
arr.values[0] = 3.14;
cout << "first element=" << arr.values[0] << endl;
cout << "size=" << arr.size() << endl;
return 0;
}
This specific example lets us define an array with a constant size.
But why can't we pass strings as template arguments in C++?
The following slide is suppose to explain it but I'm not getting where the problem is.
If someone can point it out to me and explain it I'd appreciate it.
Thanks
The short answer is, "because the standard says so". Since template arguments serve to form a type, they must be sufficiently unambiguous. The following works, though:
template <char *> struct Foo { };
char x;
int main()
{
Foo<&x> a;
}
The point is that x is now a well-defined, named object with linkage, so its address is a globally, statically known quantity. The pointer derived from a string literal does not have the same qualities; it is not the address of a named variable.
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.
This is what I want to do:
enum MyEnum
{
ONE = 1, TWO, THREE
};
template<class T>
void func()
{
cout << T::TWO << endl;
}
int main()
{
func<MyEnum>();
};
It works, but I get a warning: "warning C4482: nonstandard extension used: enum 'MyEnum' used in qualified name"
How can I do this without getting the warning
Enum is a little tricky here. The type ONE and TWO will be in the outer namespace.
So adding the type to the name results in the warning.
You could just remove the qualifier
template<class T>
void func()
{
cout << TWO << endl;
}
Since the TWO is known in the outer namespace.
You could also just move your enum to some sort of enclosing struct.
struct EnumContainer
{
enum MyEnum
{
ONE = 1, TWO, THREE
};
};
template<class T>
void func()
{
std::cout << T::TWO << std::endl;
}
int main()
{
func<EnumContainer>();
};
Now the compiler should be fine.
Enums (pre C++0x) are treated like integral types.
In fact, the notation MyEnum::TWO is garbage: there is no class or namespace MyEnum. The names ONE, TWO, and THREE are brought into the namespace where the enum is defined [in this case, the global namespace].
You should get an error like TWO is not a member of MyEnum.
One way to emulate the behavior is to put it in a struct or class, like others have suggested.
While it would be nice to use the enum as the template parameter and have it recognize each individual enum separately as you've written it, it won't happen. Instead, may I suggest that you declare the following:
template<MyEnum T>
void func(){
std::cout << T << std::endl;
}
The great thing about C++ is that the way templates are structured gives you a Turning complete system. Hence, you don't need a separate call like this, as you've declared to get each individual enum value. You can create a separate function for each value when you need it and only when you need it.
Now, getting to the other problem of your question, as #delnan commented, you can't have two different Enums with the same name. You can, however, have a class with a member variable called TWO such that:
struct Foo{
int TWO;
};
struct Bar{
int TWO;
};
template<typename T>
void func(){
std::cout << T::TWO << std::endl;
}
Hope that helps.
consider this simple and pointless code.
#include <iostream>
struct A {
template<int N>
void test() {
std::cout << N << std::endl;
}
};
int main() {
A a;
a.test<1>();
}
It is a very simple example of a function template. What if however, I wanted to replace A::test with an overloaded operator() to make it a functor?
#include <iostream>
struct A {
template<int N>
void operator()() {
std::cout << N << std::endl;
}
};
int main() {
A a;
a<1>(); // <-- error, how do I do this?
}
Certainly if the operator() took parameters which were dependent on the template, the compiler could possibly deduce the template. But I just can't figure out the proper syntax to specify template parameters with a parameterless functor.
Is there a proper way to do this?
Obviously, this code would work since it bypasses the functor syntax:
a.operator()<1>();
but that kinda defeats the purpose of it being a functor :-P.
You can only call
a.operator()<1>();
but that would not be using a functor. Functors need a non template operator(), as they must be able to be called as varname() and that won't work with your code.
To make it a real functor change your code a template class (functors are classes):
#include <iostream>
template<int N>
struct A {
void operator()() {
std::cout << N << std::endl;
}
};
int main() {
A<1> a;
a();
}
There's not another "direct" way I know other than the:
a.operator()<1>();
syntax. If you're open to changing the code, moving the template parameter to the class would work, or using a (boost|tr1)::bind to make a (boost|tr1)::function object.
You are trying to pass a template parameter to an instance of an object, which as far as I know is not allowed. You can only pass templates parameters to template functions or template objects.
a.test<1>(); and a.operator()<1>(); work because they are serving as template functions.
Use boost::bind (check out boost libraries) to fix it though.
struct A {
void operator()(int n) {
std::cout << n << std::endl;
}
};
int main(int argc, char* argv[]) {
A a;
boost::function<void()> f = boost::bind<void>(a, 1);
f(); // prints 1
return 0;
}
And you don't even have to mess with templates!
You're stuck. Have you considered something like
struct A {
template<int N>
struct B
{
void operator()()
{ std::cout << N << std::endl; }
};
template<int N>
B<N> functor() {return B<N>();}
};
int main()
{
A a;
a.functor<1>()();
}
Nope, there's no way around it. Like you said, you have to either call the operator explicitly (which defeats the purpose), or the template arguments must be able to be deduced by the compiler.