I have functions of this type:
type uniRndtype()
{
return typeValue;
}
and now I'm trying to wrap them inside another template function like this:
template<typename T>
T(* uniRndType(void))()
{
if (is_same<T, bool>::value)
{
return uniRndBool;
} else if (is_same<T, char>::value)
{
return uniRndChar;
} else
...
}
and calling it like this:
uniRndType<int>();
But I'm getting an error: "error: return value type does not match the function type"
because each return has a different type..
I there a way to make it work? Because from a runtime point of view I see no errors, only the compiler have problems.
The problem is that while the optimiser can eliminate dead code branches, the front-end (lexical, syntactic & semantic analysis) can't. Which means all code in a template instantiation must be valid. That is, even though in this:
if (is_same<T, bool>::value)
{
return uniRndBool;
}
the body will never be executed when T is char, it must still be valid C++ code. And of course it's not, because uniRndBool doesn't have the correct type.
You have two options: a hackish one which works in your particular case, and a generic one.
The hackish one is using reinterpret_cast<T(*)()> in all the return statements. For the correct T brach, it will be a no-op. The other branches will never be executed at runtime, so all will be fine.
The other solution is to use template specialisation. Since it's a bad idea to specialise function templates, you could use the well-known "delegate to class" trick:
template <class T>
struct uniRndTypeHelper;
template <>
struct uniRndTypeHelper<bool>
{
static bool (*get())() { return uniRndBool; }
};
template <>
struct uniRndTypeHelper<char>
{
static char (*get())() { return uniRndChar; }
};
template<typename T>
T(* uniRndType(void))()
{
return uniRndTypeHelper<T>::get();
}
template <typename T> T (*uniRndType())()
{
//else
...
}
template <> bool (*uniRndType())()
{
return uniRndBool;
}
template <> char (*uniRndType())()
{
return uniRndChar;
}
That's all.
edit: In principle, we must do like #Angew. but it's little troublesome
This won't work because when the compiler expands the template method for a given type the method has to be valid. Your type, T, needs to be compatible with all the return types listed, eg bool, char, etc. As I mentioned in the comments, if you passed in a std::string you wouldn't expect the method to work, would you?
One way around this is to use template specialization to indicate what you want for each type.
Compiler needs to know what types will be used by functions/methods at compile time. At this point you must instantiate this template function with types which it may receive as template parameter, like #ikh wrote here.
But, if you are using template class with template methods, you have 2 ways:
1) Simply write realization of each template method in .h file (right in the place where you declaring template class body) instead of prototypes only;
2) Or after declaring prototypes in .h file you need to instatiate this template class with template parameters which it may receive.
Related
Let's say I have a C++ class Foo. It has a templatized method setValue() that needs to accept any of the following as its argument:
Any primitive type
An object of type Bar
An object of a subclass of Bar
I want to write something like this.
template <class T>
void setValue(T& value) {
if (std::is_fundamental<T>::value)
setPrimitiveValue(value)
else {
Bar* bar = dynamic_cast<Bar*>(&value);
if (bar != NULL)
setBarValue(*bar);
}
}
But this doesn't compile. When I call the method with an int, the compiler complains that dynamic_cast can't be used on an int*. Even though that code branch doesn't get executed for primitives, the compiler still needs to compile it.
How can I make this work? Note this is a method in a class, so template specializations aren't allowed.
Since C++17 you can easily address this problem with if constexpr.
As you can expect, it can exclude an entire branch from the compilation (rather than the execution, as a normal if).
Note: the code is still subjected to syntax rules. Details are out of the scope of this answer.
template <class T>
void setValue(T& value) {
if constexpr (std::is_fundamental<T>::value)
setPrimitiveValue(value)
else {
Bar* bar = dynamic_cast<Bar*>(&value);
if (bar != NULL)
setBarValue(*bar);
}
}
The answer from Biagio Festa looks perfect as long as you can use C++17. I can't since I still need to support older compilers, but that answer led me to Constexpr if alternative which gives several alternatives. Here's the solution I ended up with which works even on C++11.
template <class T>
typename std::enable_if<std::is_fundamental<T>::value, void>::type setValue(T& value) {
setPrimitiveValue(value);
}
void setValue(Bar& value) {
setBarValue(value);
}
I have some trouble understanding templates in D.
I understand what a struct Foo(T) { } or the equivalent for a class or function does, but what is a template Bar(T) { }? how does it differ from a class, struct or function template and when would I use one?
When you see template bar(T), you can think of it as a namespace - sort of like a struct or class. Just like struct Foo(T), the contents are of course templated on the template argument, and are generally only accessible through bar!T.memberName.
I say generally, because there are some special rules. First, we have eponymous templates. If template foo(T) has a member with the exact same name as the template, then foo!T is a synonym for foo!T.foo, and the whole namespace idea sorta disappears. Other members inside foo!T are hidden and inaccessible. In fact, when you write struct Foo(T) {}, the compiler turns it into template Foo(T) { struct Foo {} }.
The other special case is mixin templates, which are basically snippets that will be dropped in verbatim when you instantiate them. That is, this code (note the mixin keyword before template):
mixin template Foo() {
int i;
}
struct Bar {
mixin Foo!();
}
is functionally equivalent to this code:
struct Bar {
int i;
}
Now, why would you use just template? The first is template metaprogramming. If you look at std.traits or std.meta, those modules are filled with templates. Not mixin templates, not templated structs, classes or functions, but just templates. These operate on the values and types passed to them, and returns some kind of value or type.
A very simple example of a template used like this is std.meta.Reverse. It takes a list of arguments and reverses them, and looks like this:
template Reverse(TList...)
{
static if (TList.length <= 1)
{
alias Reverse = TList;
}
else
{
alias Reverse =
AliasSeq!(
Reverse!(TList[$/2 .. $ ]),
Reverse!(TList[ 0 .. $/2]));
}
}
Another case where you'd want to use templates is if your templated type should be elided in some cases. Say you're making your own Nullable(T), and you want Nullable!(Nullable!T) to always be Nullable!T. If you just wrote struct Nullable(T) {}, you would not get this behavior, and you'd end up with double-nullable types. The solution is to use a template constraint:
struct Nullable(T) if (!isNullable!T) {}
and a template to handle the degenerate case:
template Nullable(T) if (isNullable!T) {
alias Nullable = T;
}
I hope this was of some help, and please ask if anything's unclear. :)
Well, technically,
struct S(T)
{
...
}
is equivalent to
template S(T)
{
struct S
{
...
}
}
and
auto foo(T)(T t)
{
...
}
is equivalent to
template foo(T)
{
auto foo(T t)
{
...
}
}
It's just that the shorter syntax is provided to make things cleaner for a common use case. template creates a template for code generation. Nothing within that template exists as real code before the template is instantiated with arguments, and the code that gets generated depends on the template arguments. So, semantic analysis for a template is not done until until it's instantiated.
Part of what's happening with structs, classes, and functions which have the template as part of their declaration instead of explicitly declaring the template to wrap them is what's called an eponymous template. Any template that has a symbol in it with the same name as the template is replaced with that symbol when the template is used. e.g.
template isInt(T)
{
enum isInt = is(T == int);
}
could then be used in an expression such as
auto foo = isInt!int;
and the value of enum isInt.isInt is used in the expression in place of the template. This technique is used heavily with helper templates for template constraints. e.g. isInputRange in
auto foo(R)(R range)
if(isInputRange!R)
{...}
isInputRange is defined as an eponymous template that results in true if the given type is an input range and false otherwise. In a way, it's kind of like having a function for operating on types, though it can operate on values as well, and the result doesn't have to be bool. e.g.
template count(Args...)
{
enum count = Args.length;
}
or
template ArrayOf(T)
{
alias ArrayOf = T[];
}
There's also a shortcut syntax for eponymous templates which aren't user-defined types or functions if they don't have any other members. e.g.
enum count(Args...) = Args.length;
alias ArrayOf(T) = T[];
And as I said, an eponymous template can be a bit like having a function to operate on a type, and that's what they're used for when complicated operations need to be done on types. For instance, using that ArrayOf template with std.meta.staticMap, you can do something like
alias Arrays = staticMap!(ArrayOf, int, float, byte, bool);
static assert(is(Arrays == AliasSeq!(int[], float[], byte[], bool[])));
This can be extremely useful in template constraints (or other eponymous templates to be used in template constraints), or it can be used with something like static foreach to more explicitly generate code. e.g. if I wanted to test some code with all string types, I could write something like
alias Arrays(T) = AliasSeq!(T[],
const(T)[],
const(T[]),
immutable(T)[],
immutable(T[]));
unittest
{
import std.conv : to;
static foreach(S; AliasSeq(Arrays!char, Arrays!wchar, Arrays!dchar))
{{
auto s = to!S("foo");
...
}}
}
These techniques are typically used quite heavily in metaprogramming. They can be used on values in addition to types, but it's usually more efficient to use CTFE for values rather than putting them in an AliasSeq and using various eponymous templates on them. For instance, years ago, Phobos used to have the eponymous template Format which was used to generate strings at compile time similarly to how std.format.format does that at runtime, but once CTFE was improved to the point that format could be used at compile-time, it made no sense to use Format instead of format, because Format was horribly slow in comparison (doing a lot of recursive template instantiations can get to be expensive). So, using template metaprogramming is still required when operating on types, but if you can do what you need to do with CTFE, that's generally better.
If you're looking for metaprogramming tools in Phobos, std.traits and std.meta are the main place to look, though some are scattered throughout Phobos depending on what they're for (e.g. the range-specific ones are in std.range.primitives).
Also, similarly to how you can mixin strings, you can mixin templates. e.g.
template foo(T)
{
T i;
}
void main()
{
mixin foo!int;
auto a = i;
}
So, the code that's generated by the template essentially gets copy-pasted where you mix it in. Optionally, you can put mixin on the template declaration to make it illegal to use it as anything other than a mixin. e.g.
mixin template foo(T)
{
T i;
}
Personally, I usually just use string mixins for that sort of thing, but some folks prefer template mixins.
Let's say I have several functions defined like this:
template <typename T>
inline void read<bool>(T **data) {
//some code
}
template <typename T>
inline void read<double>(T **data) {
//some other code
}
template <typename T>
inline void read<int>(T **data) {
//also different code
}
Now, I create another function defined like this:
template<typename T>
inline void readMultiple(T **data, int counter) {
for (int i = 0; i < counter, ++i) {
read<T>(data);
}
}
(1)That would call the appropriate read<T>(T **data) implementation based on the type T, right?
(2)If I were to specify a type that is not one of the three above, I'd get a compilation error, since that function is not defined, right?
(3)Also, can I make this call:
double **d;
read<double>(d);
to ensure that I called the implementation for double?
I know I'd get the same result without the <double> part, but this way I'm ensuring that double is passed to the function, where as doing it without <double> would allow for d to be a int or a bool and the code would still compile, silently introducing an error.
(1)That would call the appropriate read<T>(T **data) implementation based on the type T, right?
Yes, assuming the specializations are visible at the point where read<T>(data) is encountered.
(2)If I were to specify a type that is not one of the three above, I'd get a compilation error, since that function is not defined, right?
You haven't provided your declaration of the template read() function, so this can't be answered. Assuming that you have declared it like template <typename T> void read(T**); and have not defined it anywhere then yes, you would get a link-time error when the linker is unable to find an implementation of the requested specialization.
(3)Also, can I make this call:
double **d;
read<double>(d);
to ensure that I called the implementation for double?
You can, though <double> is superfluous and will be inferred.
... silently introducing an error.
If the thing you're passing is a bool** then it would not be an error to use the bool specialization. I don't really see any benefit from explicitly providing the template arguments. If bool** is the wrong type then presumably you would be getting errors somewhere else, anyway.
I guess it depends on what you mean by "silently introducing an error." It's not clear what kind of error you're trying to prevent. I can come up with a contrived example, but contrived examples rarely represent real-world dangers.
Two side notes:
The syntax for your specializations is incorrect. It should be template <> inline void read<bool>(bool **data) { /* ... */ } for example.
There's no need for templates here at all, you can just have three function overloads. Having an undefined template function with explicit specializations is an anti-pattern; overloads are the recommended way to implement the same thing.
Whenever I create a template I know to pass it in as function arguments, but is there any particular reason why I cannot use templates inside of my main function?
template <class Tmp>
int main()
{
Tmp pizza;
}
But passing as parameter will always work
template <class Tmp>
Tmp add(Tmp x, Tmp y)
{
return x+y;
}
The above code will not run and next to my attempted variable declaration line it state "Unknown type 'Tmp' ", but I assumed that because I declared template outside of my main function it would take this into account. Is there any particular reason why this is so? It seems as if everyone just uses templates inside function parameters and nothing more.
You're nearly there. But C++ is a statically-typed language, so the compiler needs to know the type for pizza at compile-time. This
template <class Y> struct/*members are public by default*/ Tmp
{
typedef Y type;
};
int main()
{
Tmp<int>::type pizza; /*pizza will be an int*/
}
is legal.
is there any particular reason why I cannot use templates inside of my main function
There's no reason you can't, but your code does not use templates inside your main function. Rather, your code is trying to define main to be a function template. This is no good, because the signature of main is specified in the standard and it's not a function template. Granted, implementations are permitted to specify alternatives, but this doesn't help you because your implementation doesn't specify any template function alternatives. My compiler (gcc) gives a more forthright error message than yours, it says:
error: cannot declare ‘::main’ to be a template
You are writing as if you believe that Tmp is called a template. If so, then correct that by looking back at your textbook/tutorial/whatever. Tmp is not a template. It is a template parameter. In your second code snippet, add is a function template, and Tmp is still not a template, it's the template parameter of add.
You can use template parameters inside the template whose parameters they are. For example, the following is fine:
template <class Tmp>
Tmp add(Tmp x, Tmp y)
{
Tmp total = x + y;
return total;
}
Your problem is just that when you tried this you tried it in main, which cannot be a template.
Templates are not code. Templates are ... well they are templates. Before you can call a template function it has to be instantiated. E.g.
template <class T> T foo(T x) { return T;}
This is just a template, ie if you write this alone the compiler will not create a single line of code for this. Only when you instantiate and use it the compiler will do something:
int main() {
int x = 0;
int y = foo<int>(x); // compiler instantiates the template and calls the int instance
}
In your first snippet the compiler does not know what type it should use to instantiate the template. Moreover, you cannot make main a template, because the entry point of any program has to be int main().
PS:
It seems as if everyone just uses templates inside function parameters and nothing more.
There are more things that one can do with templates. I like to think about templates as the way to parametrize my code whenever the parameter can be choosen at compile time. Consider this (a bit contrived) example:
// template taking a functor as argument
// (more precisely: a default constructible callable type)
template <typename op,typename T> void plug(T x) {
std::cout << "op(" << x << ") = " << op()(x) << "\n";
}
// a simple functor
template <typename T>
struct identity { T operator()(T x){return x;} };
int main() {
plug<identity<double>,double>(2.0);
}
// prints:
// op(2) = 2
Once instantiated, the parameter does not appear as function parameter, but it rather controls what the (templated) function is actually doing with its parameter.
Why is the following code valid
template<class T>
T AddThree(T input)
{
return input + 3;
}
template<class T> // If I remove this line it won't compile
T SubtractThree(T input)
{
return input - 3;
}
But if I comment out the line indicated it won't compile? How come the compiler doesn't still know about template<class T> from the first time it is declared (like anything else declared in the body of the file)?
You can think of it as part of the function signature. Maybe it's easier to see the connection if you write the full declaration on one line:
template<class T> T AddThree(T input)
{
return input + 3;
}
It is like how you need to declare the parameters for each function. You would not expect this to work:
std::string AddThree(std::string input)
{
return input + "3";
}
std::string SomethingElse(input)
{
// ...
}
Here, like with the template parameters, you need to declare input in the second function as well as the first. It is the scoping rules of the language :)
Notice the position of declaration terminators (semi-colons or function bodies). template <class T> is not a declaration by itself—it's not something that would be in scope for the entire file. It's part of the declaration of the function template in question.
How would the compiler know that SubtractThree is a templated function? Clearly you don't want a single template declaration to mean everything afterword is a template. You could also imagine designing the C++ spec such that every unrecognized class (T in this case) is seen as a template, but then you risk making template functions when you misspell classes.