If I have a template class with a default template type, I have to write the template angle brackets. Is it somehow possible to avoid this?
Example:
template <typename T=int>
class tt {
public:
T get() { return 5; }
};
...
tt<> t; // how to avoid <>
std::cout << t.get() << std::endl;
Until now i've did this by a separate namespace and redeclaring the class:
namespace detail_ {
template <typename T=int>
class tt {
public:
T get() { return 5; }
};
}
class tt : public detail_::tt {}
...
tt t;
std::cout << t.get() << std::endl;
The problem is, if I want to use the class with an other type I have to go over namespace detail_. Is there another solution, which I didn't see yet.
... if I want to use the class ...
This is a common source of confusion. A class template is not a class, but a template from which classes are generated. The angle brackets is what tells the compiler that you want to generate a class out of the class template with the given template arguments, without the angle brackets what you have is a template.
template <typename T = int>
struct TemplateClass { /*...*/ };
template <template <typename> class T>
void f() {
T<int> t; // ...
}
template <typename T>
void g() {
T t; // ...
}
f<TemplateClass>(); // Accepts a template with a single type argument
g<TemplateClass<> >(); // Accepts a type, that can be generated out of the template
The language does not allow the coexistence of a template and a type with the same name in the same namespace, so the answer is that it cannot be done. You can create a type alias but you will have to give it a different name.
You can use typedef...
typedef tt<> tt_;
And then simply use tt_.
Since C++17, because of class template argument deduction, things have changed.
tt and tt<> are not the same thing: types and class templates were different and continue to be treated differently.
Anyway in simple scenarios like the one in your example, C++17 assumes what you mean and the <> aren't needed anymore.
Further details:
Template default arguments (specifically https://stackoverflow.com/a/50970942/3235496);
Why is <> required when specifying a template class which has defaults for all its template parameters?
Related
I'm tyring to understand std::enable_if and the benefits of using it over a static_assert / regular template specialitzation.
After reading around I found:
This is useful to hide signatures on compile time when a particular condition is not met, since in this case, the member enable_if::type will not be defined and attempting to compile using it should fail. http://www.cplusplus.com/reference/type_traits/enable_if/
My question then is: Why the compiler blames me by saying that class C is already declared?, when only one of the declaraions should be avaiable at a time.
class Interface{};
class Foo : public Interface{};
template <class T, typename = typename std::enable_if<std::is_base_of<Interface,T>::value>::type>
class C{
// Some custom implementation
}
template <class T, typename = typename std::enable_if<!std::is_base_of<Interface,T>::value>::type>
class C {
//Some fallback / default implementation
}
int main() {
C<Foo> myVariable;
}
Same behaviour in Godbolt: https://godbolt.org/z/cbfhG9q54
Thanks in advance!
You cannot overload class templates like you can function templates, buy you can partially specialize them (which you cannot do with function templates):
#include <ios>
#include <iostream>
#include <type_traits>
class Interface
{};
class Foo : public Interface
{};
template <class T, typename = void>
struct C
{
// Some default impl.
static constexpr bool is_default_impl{true};
};
template <class T>
struct C<T, std::enable_if_t<std::is_base_of_v<Interface, T>>>
{
// Some custom implementation.
static constexpr bool is_default_impl{false};
};
int main()
{
std::cout << std::boolalpha
<< C<int>::is_default_impl << " " // true
<< C<Foo>::is_default_impl; // false
}
Note that this examples requires C++17 for the variable template std::is_base_of_v which is a short-hand constant the value member of the std::is_base_of trait, and C++14 for the alias template std::enable_if_t, which aliases the type member alias declaration of the std::enable_if trait.
So first, apologies for terminology - I'm not sure if template prototype is the correct term. By this I mean :
template <class T, class X>
class TemplatePrototype
{
// code
};
I have a situation where I have a function that creates a template object based upon template arguments to that function.
template <class T, class X>
void doSomething()
{
TemplatePrototype<T, X> aTemplateTX;
aTemplateTX.doSomethingElse();
}
However, there are about 15 different versions of TemplatePrototype, which all have the same interface but different execution (TemplatePrototype is provided by another library). As a result, I have a lot of code that looks like this:
template <class T, class X>
void doSomethingWithOne()
{
TemplatePrototypeOne<T, X> aTemplateTX;
aTemplateTX.doSomethingElse();
}
template <class T, class X>
void doSomethingWithTwo()
{
TemplatePrototypeTwo<T, X> aTemplateTX;
aTemplateTX.doSomethingElse();
}
As a consequence of the architecture, I must know which TemplatePrototype I am going to use before I know the actual types T and X. I would like to see something like this:
template <class T, class X, class Prototype>
void doSomething()
{
Prototype<T, X> aPrototype;
aPrototype.doSomething();
}
But where I have specified part of the template arguments in advance - i.e I specify Prototype before I know T and X. Obviously, this is not possible in C++.
Equally, I cannot pass the Prototype as a template argument because it will still result in huge amounts of duplicate code.
Some important facts : I know the range of all possible inputs.
So I could theoretically use a macro to define each possible template specialisation and insert them into a container, which I would then use to access the specialisation I need. However, I am looking for a more 'elegant' solution - is it possible to pass template prototypes without specialising them as an argument to a template class, and then instantiate later when a function is called? Example:
template <class Prototype>
class Holder
{
template <class T, class X>
void doSomething()
{
Prototype<T, X> aPrototype;
aPrototype.doSomethingElse();
}
};
As far as I know this is impossible, but I was wondering if the SO community had some folks who know a solution?
EDIT:
So I have implemented this as my solution, thanks to the answers below!
#include <iostream>
template <typename T>
struct Foo
{
Foo() { aPtr = 0; }
T* aPtr;
};
template <template<typename> class C>
struct Bar
{
template <class T>
void doSomething()
{
C<T> aClass;
if (aClass.aPtr)
std::cout << "Hello world" << std::endl;
}
};
int main()
{
Bar<Foo> aFoo;
aFoo.doSomething<int>();
return 0;
}
This enables me to specify which TemplatePrototype I wish to use, before I can know the template parameters.
Yes, use a template template parameter, e.g.
template <typename T>
struct Foo
{
};
template <template<typename> class C>
struct Bar
{
};
then
Bar<Foo> b;
You're looking for template template parameters.
In the template parameter list, instead of just:
class TemplatePrototype
specify your prototype as a class template which itself has two template type parameters (without giving them a name here), like:
template<class,class> class TemplatePrototype
//^^^^^^^^^^^^^^^^^^^
This will result in a function like:
template <class T, class X,
template<class,class> class TemplatePrototype>
void doSomething()
{
TemplatePrototype<T, X> aTemplateTX;
aTemplateTX.doSomethingElse();
}
Invocation example:
doSomething<T, X, TemplatePrototypeOne>();
To become independent of the number of template parameters you pass to your "prototype" (here it was 2, namely T and X), you can use variadic templates (since C++11).
For this, first move the prototype template parameter to the first position:
template <template<class,class> class TemplatePrototype,
class T, class X>
Then, replace class T, class X with class ...Ts, which is a placeholder of an arbitrary number of type parameters. Also, in the template template parameter list, replace class,class with class.... And in the instantiation within the function implementation, replace <T, X> with <Ts...> to "expand" the parameter pack.
The result then looks like this:
template <template<class...> class TemplatePrototype,
class ... Ts>
void doSomething()
{
TemplatePrototype<Ts...> aTemplateTs;
aTemplateTs.doSomethingElse();
}
Live demo
I went into trouble understanding the following codes:
#include <iostream>
using namespace std;
template <class PixType, bool B = PixType::is>
class Test {
public:
void print() {
cout << "PixType B=false" <<endl;
}
};
template <class PixType>
class Test<PixType,true> {
public:
void print() {
cout << "PixType B=true" <<endl;
}
};
class PT {
public:
static const bool is = false; // here is the magic
};
int main() {
Test<PT> t;
t.print();
}
I have 4 questions:
What's the difference between the first template test class(with <> right after template instead of the class name) and the second one(with <> after class name Test).
Why can two same classes(both are named Test) exist at the same time.
In fact, when the is in class PT is set to be true, the program will print out PixType B=true, otherwise PixType B=false, and I don't know the magic here.
I tried to change the second template Test class to be like:
template <class PixType, bool B= true>
class Test {
public:
void print() {
cout << "PixType B=true" <<endl;
}
};
But the compiler will warn me of name conflict.
I am really new to these template stuff, and got really confused by these lines of codes. And I don't know how to search for this trick. In most articles about C++ templating, they just talk about some basic ideas and usages about template.
Any help will be greatly appreciated.
Point 1 What's the difference between the first template test class(with <> right after template instead of the class name) and the second one(with <> after class name Test).
Response The first one is the main class template definition. The second one is a specialization of the class template where the second parameter of the template is true.
If you didn't have the second one, the first one will be used regardless of whether the second parameter of the template is true or false.
Point 2 Why can two same classes(both are named Test) exist at the same time.
Response In your case, the second one is a specialization of the first one. When you use:
Test<int, true> a;
The compiler knows to use the specialization to generate code for Test<int, true>. When you use:
Test<int, false> b;
The compiler know to use the first one to generate code for Test<int, false>.
Point 3 In fact, when the is in class PT is set to be true, the program will print out PixType B=true, otherwise PixType B=false, and I don't know the magic here.
Response As I explained above, when the second parameter is true, the compiler uses the second class template. Otherwise, it uses the first class template. I hope there is no confusion about that any more.
Point 4 I tried to change the second template Test class to be like:
template <class PixType, bool B= true>
class Test {
public:
void print() {
cout << "PixType B=true" <<endl;
}
};
But the compiler will warn me of name conflict.
Response
Class templates can only be specialized, they cannot be overloaded.
template <typename A, typename B> class C1 {};
template <typename A> class C1 {};
The above is not supported by the language.
template <typename A, typename B> class C1 {};
template <typename A> class C1<A, A*> {};
The above is supported by the language. The second class template is a specialization of the first class template.
What you are trying to do is provide a default value for the second parameter but the name used to define the class template is same. The second one is a different class template not a specialization of the first class template.
I'm trying to have a different template specialization for classes which have an inner class with a particular name present. I've taken a clue from here and tried the following:
#include <iostream>
template< typename T, typename Check = void > struct HasXYZ
{ static const bool value = false; };
template< typename T > struct HasXYZ< T, typename T::XYZ >
{ static const bool value = true; };
struct Foo
{
class XYZ {};
};
struct FooWithTypedef
{
typedef void XYZ;
};
int main()
{
// The following line prints 1, as expected
std::cout << HasXYZ< FooWithTypedef >::value << std::endl;
// The following line prints 0. Why?
std::cout << HasXYZ< Foo >::value << std::endl;
return 0;
}
As you can see, if I test for a typedef-defined type in FooWithTypedef, it works. However, it does not work if the type is a genuine inner class. It also only works when the typedef-ed type in FooWithTypedef matches the default value of the second argument in the initial template declaration (which is void in my example). Could one explain what is going on here? How does the specialization process work here?
Answer to the initial question
The template specialization you defined here:
template <typename T> struct HasXYZ <T,typename T::XYZ>
{ static const bool value = true; };
will take effect when somebody uses the data type HasXYZ<A,A::XYZ> for some data type A.
Note that, whatever A is, A::XYZ is a data type totally independent of A. Inner classes are data types in their own right. When you use A as the first template argument, there is absolutely no reason for the compiler to assume that you want to use something called A:XYZ as the second argument, even if an inner class of that name exists, and even if doing so would lead the compiler to a template specialization that matches the template arguments exactly. Template specializations are found based on the template arguments provided by the coder, not based on further possible template arguments.
Hence when you use HasXYZ<Foo>, it falls back to using the default template argument void for the second parameter.
Needless to say that if you were to use HasXYZ<Foo,Foo:XYZ> explicitly, you'd get the expected output. But that obviously is not what you intended.
I am afraid the only way to get what you need is std::enable_if (or something that works in a similar way).
Answer to the additional question (after update)
Consider the simplification below:
template <typename T, typename Check = void>
struct A
{ static const bool value = false; };
template <typename T>
struct A<T,void>
{ static const bool value = true; };
The primary definition specifies a default argument of void for the second template parameter. But the specialization (second definition above) defines what class A actually looks like if the second template parameter really is void.
What this means is that if you use, say, A<int> in your code, the default argument will be supplemented so you get A<int,void>, and then the compiler finds the most fitting template specialization, which is the second one above.
So, while default template arguments are defined as part of the primary template declaration, making use of them does not imply that the primary template definition is used. This is basically because default template arguments are part of the template declaration, not the template definition (*).
This why in your example, when typedef void XYZ is included in FooWithTypedef, the second template parameter defaults to void and then the most fitting specialization is found. This works even if in the template specialization the second argument is defined as T::XYZ instead of void. If these are the same at the time of evaluation, the template specialization will be selected (§14.4 "Type equivalence").
(*) I didn't find a statement in the Standard that actually says it so clearly. But there is §14.1/10, which describes the case where you have multiple declarations (but only one primary definition) of a template:
(§14.1/10) The set of default template-arguments available for use with a template declaration or definition is obtained by merging the default arguments from the definition (if in scope) and all declarations in scope in the same way default function arguments are (8.3.6). [ Example:
template<class T1, class T2 = int> class A;
template<class T1 = int, class T2> class A;
is equivalent to
template<class T1 = int, class T2 = int> class A;
].
This suggests that the mechanism behind default template arguments is independent of that used to identify the most fitting specialization of the template.
In addition, there are two existing SO posts that refer to this mechanism as well:
This reply to Template specialization to use default type if class member typedef does not exist
Default values of template parameters in the class template specializations
Here is another version that detects the presence of the inner class :
#include <iostream>
template< typename T >
struct HasXYZ
{
typedef char yes;
typedef struct{ char d[2]; } no;
template<typename T1>
static yes test( typename T1::XYZ * );
template<typename T1>
static no test(...);
static const bool value = ( sizeof( test<T>(0) ) == sizeof( yes ) );
};
struct Foo
{
class XYZ {};
};
struct Bar
{
class ABC {};
};
int main()
{
std::cout << std::boolalpha << HasXYZ< Foo >::value << std::endl;
std::cout << std::boolalpha << HasXYZ< Bar >::value << std::endl;
}
A::XYZ would need to void to have the partial specialization selected, which can never be the case for a class type. One way to make it work is using a fake dependant void typename:
template<class T>
struct void_{ typedef void type; };
template<class T, class = void>
struct has_XYZ{ static bool const value = false; };
template<class T>
struct has_XYZ<T, typename void_<typename T::XYZ>::type>{
static bool const value = true;
};
For an explanation on how this works, see this question.
Why can't I do this:
template<template<class E>class Derived>
struct X
{
static void f()
{
Derived<E>::value;
}
};
The problem that I have is that I cannot compile this code for the reason that I'm getting an error saying that param E hasn't been declared. Is there a way that I can use this formal param or not?
Parameters of template template parameters don't get arguments, and therefore don't usually have names. Partial specialization is the exception to this rule. Try this instead:
template<class> // Derived<E> is only only parameter
struct X; // but you actually need two parameters, Derived and E
template< template <class> class Derived, class E >
struct X< Derived< E > > // so use partial specialization.
{
static void f()
{
Derived<E>::value; // only reason to want this is to
Derived<int>::value; // use different specializations
}
};
Of course, if you don't need to re-specialize on Derived< something_else >, just ignore the fact that Derived<E> is a template specialization:
template<class Derived>
struct X
{
static void f()
{
Derived::value;
}
};
X< my_class< something > > my_x; // a specialized class template is a class
Your template parameter Derived is a template itself, E is its formal parameter.
You need to pass a value for it, too.
Maybe you need the following:
template<template<class E>class Derived, class T>
struct X
{
static void f()
{
Derived<T>::value;
}
};
You can't use that parameter because it is just there to mean that Derived is a template with exactly one type argument.
You'd call f like this:
template <class T>
struct ZZZ {};
X<ZZZ>::f();
^^^
Note that there is no E in this instantiation.
Unless there is a reason to use template templates, you could just use a regular template, else you'll need to pass E as a separate argument, making the call look like this:
X<ZZZ, int>::f();
You just have your syntax a bit muddled.
template<class E>
struct X
{
static void f()
{
Derived<E>::value;
}
}
should work fine.