Info
I am trying to use a template alias to improve the readabilty of my code. Ideally I would like to the alias to have a default argument such that if I leave out the template it uses the default (exactly with template functions and template classes).
The code would look like
template<typename T = double>
struct mystruct {};
template<typename T = double> using myalias = mystruct<T>;
int main(void) {
myalias MyStructWithDouble; // causes compilation error
myalias<int> MyStructWithInt;
return 0;
}
The compiler (g++ 4.7 in this case) is quite happy with the inclusion of the = double in the alias definition but it seems to then ignore this.
I tried something like "specializing" the alias as well but there the compiler baulked.
Question
Why does the compiler accept the default in the defintion if we are not allowed to use it? Secondly, is there a way of acheiveing this?
Motivation
This example is very simple but in my real code the alias would save a lot of typing (there are more than one template parameter)
Just like with class templates, you still need to supply an empty template argument list:
myalias<> MyStructWithDouble; // compiles
Related
Below is a simplified code showing my problem.
Yes I tried and I could not find any similar problem through Google.
template<typename T>
class MyClass {
public:
using TypeFromTemplate = T;
};
MyClass<uint32_t> & MyObject = MyOtherObject;
I would like to be able to get the templated type through something like MyObject::TypeFromTemplate or MyObject.TypeFromTemplate (both doesn't work).
I figured out something like that: RemoveReference<decltype(MyObject)>::Type::TypeFromTemplate, but it's a little messy to use it a lot.
RemoveReference<T> does exactly what the name suggests - provides a Type without the reference.
This code is very simplified - my class takes multiple template parameters, which do not have short names to type out, the objects are declared in the header, and the source files are very interested in accessing the template parameters for their own declarations, otherwise I would not bother with something like that.
You can use using-declaration to alias your TypeFromTemplate:
template<class T>
using TypeFromTemplate_t = typename RemoveReference<T>::TypeFromTemplate;
which makes it relatively easy to extract the template type:
MyClass<uint32_t>& MyObject = MyOtherObject;
TypeFromTemplate_t<decltype(MyObject)> value = 0;
When compiling this snipet in godbolt, most compilers generate two different get methods (different symbol in the assembly window):
template<typename T>
struct Field { T impl; };
template<typename T>
using CurrentField = Field<T>;
template<template <typename> class F>
struct Encompassing { F<int> member; };
auto get(Encompassing<Field> const& instance)
{
return instance.member.impl;
}
auto get(Encompassing<CurrentField> const& instance)
{
return instance.member.impl;
}
I see CurrentField in symbols even if it is an alias. Only gcc complains about redefinition (as expected).
C++ reference on type_alias says
It does not introduce a new type
so I think it is not supposed to behave like this, am I wrong?
Actually most compiler seems to behave like the alias template was substituted with a class Trait like
template<typename T>
struct CurrentField
{
alias type = Field<T> ;
};
Edit:
Here is a more representative example of What I try to achieve on Godbolt. Note that it compiles since there is a single source and no linking but the msvc assembly shows it generated both the pre-instantiated signatures and user calls signatures.
There are 4 parts:
1. a container library with multiple kind of templates like StackField and HeapField,
2. an utility library with member methods like size, with the field as template argument (like the second workaround you proposed),
3. implementations are hidden and pre-instantiated in the c++ for different fields
4. users link their application A and B against this library, using aliases like AField and BField. It works with gcc but link fails in msvc because the signature of my pre-instantiated implementations and the users calls don't match
It is true that an alias template does not introduce a new type. But your class template takes a template as parameter, not a type. Both Field and CurrentField are templates. So this boils down to the question of whether CurrentField should count as the same template as Field or as a separate template. This is CWG issue 1286. See also this thread. GCC follows the first interpretation, clang and MSVC follow the second…
A workaround would seem to be to break the direct mapping of CurrentField to Field by having it go through a helper template:
template <typename T>
struct CurrentFieldHelper { using type = Field<T>; };
template <typename T>
using CurrentField = typename CurrentFieldHelper<T>::type;
working example here
I'm afraid there is no way to achieve the opposite, i.e., make all compilers treat get(Encompassing<CurrentField> const &) as the same function as get(Encompassing<Field> const &). It's hard to suggest a workaround for this particular problem without knowing more about your actual code. A simple solution that might or might not work for your actual code would be to make size a function template that unpacks instance.member and then forwards it to a common function that does the actual work:
template <template <typename> class F>
auto size(Encompassing<F> const& instance)
{
return size(instance.member);
}
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.
I have a struct being used somewhere which is declared as:
struct Foo
{
someArray[64];
//...other stuff
};
It is used extensively in many places, and I would like to change it to this:
template <size_t N = 64>
struct Foo
{
someArray[N];
//...other stuff
};
because there is one place (well four to be exact) where this struct needs to be used with a 128 byte array for correctness, but the penalty it introduces for ALL the other uses is not worth paying. In providing a default template argument I was hoping it would go through transparently, except for those in the know-how who need a wider internal array which would then declare Foo<128>. Unfortunately, it seems to force every use of it to say Foo<>. Is there a way around this?
You cannot omit the angular brackets when instantiating a class template.
However, you can give a different name to your Foo class template (say, FooN) and then provide a type alias such as:
typedef FooN<> Foo;
This way, clients who were using the original, non-template version of Foo won't have to be changed, and clients that need the flexibility of overriding the default N can use the generic class template:
FooN<128> obj;
To answer the question first: No there isn't a way to use it without <>. However that doesn't mean you can't do something else to keep your codebase intact.
The easiest solution is to rename templated variant to something else and provide a Typedef for the name Foo:
template <size_t N = 64>
struct GenericFoo
{
someArray[N];
//...other stuff
};
typedef GenericFoo<64> Foo;
This way you can keep using Foo in all the other instances and have the option of using GenericFoo<Whatever> when you need fine grained control.
namespace generic
{
template <int N> class Foo {};
}
// user code
typedef generic::Foo<64> Foo; // common users
// OR
using generic::Foo; // rare users
I'm trying to find is there's a way to check if a class is a functional because i want to write a template which uses it?
Is there an easy way to do this? Or do I just wrap things in a try/catch? Or perhaps the compiler won't even let me do it?
If you have a function template written like:
template <typename T>
void f(T x)
{
x();
}
you will be unable to instantiate it with any type that is not callable as a function taking no arguments (e.g., a class type that overloads operator() taking no arguments is callable as a function that takes no arguments). You would get a compilation error if you tried to do so.
This is the simplest way to require the type with which a template is instantiated to have certain properties: just rely on the type having those properties when you write the template, and if the type doesn't have one of the required properties, it will be impossible to instantiate the template with that type.
There are quite a few ways a parameter type can be applicable to the call syntax
Type is a pointer or reference to a function type, or
Type is a class-type which has a conversion function to one of the types in 1., or has an applicable operator().
The current C++ cannot check for 2., so you are left without checking, like the other answers explain.
This would fall under doing it and getting a compiling error. When the code is compiled the template function or template classes are are expanded for the types used as if there were duplicate copies of that template code, one for each type.
So you can basically do whatever and as long as all the types used for your templates support it you have no problem. If they don't support it you have a compiling error and you can't run your code without fixing it.
template <typename T>
void DoIt(T a)
{
a.helloworld();//This will compile fine
return a();//This will cause a compiling error if T is B
}
class A
{
public:
void a.helloworld(){}
void operator()(){}
};
class B
{
public:
void a.helloworld(){}
};
int main(int argc, char**argv)
{
A a;
B b;
DoIt(a);
DoIt(b);//Compiling error
return 0;
}
If you actually need a test to see if type T implements an operator() of some given signature then you could use the same SFINAE trick used to identify the existence of any other class member that is discussed here: C++ "if then else" template substitution