I'm trying to make a template generic with a struct and substruct,
but my code fail to infer the correct template.
this is the abstraction of my code
#include <iostream>
using namespace std;
struct A{
};
struct B{
};
struct AA:public A{
};
struct BB:public B{
};
template<class container>
class Base{
};
template<class container>
class Derived:Base<container>{
Derived() = delete;
};
template<>
class Derived<A>:Base<A>{
};
template<>
class Derived<B>:Base<B>{
};
int main() {
Derived<AA> a;
return 0;
}
and got error
error: call to deleted constructor of 'Derived<AA>'
i wish struct A and its subclass can be used with
template<>
class Derived<A>:Base<A>{
};
how can I do it, or what material should I refer to?
thx for help!
You can use the partial specialization like
// primary template
template<class container, class = void>
class Derived : Base<container> {
Derived() = delete;
};
// partial specialization for A and its derived classes
template<class container>
class Derived<container, std::enable_if_t<std::is_base_of_v<A, container>>> : Base<container> {
};
and also full specialization if necessary.
// full specialization for B
template<>
class Derived<B, void> : Base<B> {
};
LIVE
Related
In curiously recurring template pattern I need to change nested type T of TDerivedClass<T> type. Is there a way to specify Base by not fully specified Derived1 class? Something like that: class Derived1 : public Base<T, Derived1<"NOT SPECIFIED TYPE SYNTAX">>, and then fully specify Derived1 but inside Base functions as TDerivedClass<int>. Or is there any other way to change T for this specific part of code?
template<typename T, typename TDerivedClass>
class Base
{
public:
void f()
{
std::vector<T> a;
TDerivedClass b;
TDerivedClass<int> c; // <- want to change T to arbitrary type (to int for example) without changing T
}
};
template<typename T>
class Derived1 : public Base<T, Derived1<T>>
{
};
template<typename T>
class Derived2 : public Base<T, Derived2<T>>
{
};
You probably want template template parameter:
template <typename T, template <typename> class TDerivedClass>
class Base
{
public:
void f()
{
std::vector<T> a;
TDerivedClass<T> b;
TDerivedClass<int> c;
}
};
template<typename T>
class Derived1 : public Base<T, Derived1>
{
};
template<typename T>
class Derived2 : public Base<T, Derived2>
{
};
You can pass the template class specifically:
template<typename T, template<typename> class TDerivedTemplate>
class Base
{
using TDerivedClass = TDerivedTemplate<T>;
public:
void f()
{
std::vector<T> a;
TDerivedClass b;
TDerivedTemplate<int> c;
}
};
template<typename T>
class Derived1 : public Base<T, Derived1> // Pass the template (Derived1) to instantiate new classes from
{
};
// Since you're changing the pattern anyways, you might as well
// have it detect the template from the type
template<typename TDerivedClass>
class Base;
template<template<typename> class TDerivedTemplate, typename T>
class Base<TDerivedTemplate<T>> {
using TDerivedClass = TDerivedTemplate<T>;
public:
void f() { /* Same as above */ }
}
template<typename T>
class Derived1 : public Base<Derived1<T>>
// Automatically gets the template. Also means it's harder to use Base<> wrong.
{
};
Or you can use a rebind type trait:
template<typename ToRebind, typename... NewTypes>
struct rebind;
template<template<typename...> class Template, typename... CurrentTypes, typename... NewTypes>
struct rebind<Template<CurrentTypes...>, NewTypes...> {
using type = Template<NewTypes...>;
}
// Used like
TDerivedClass b;
typename rebind<TDerivedClass, int>::type c;
I'm trying to write a template class that defines its template based on the template implementation of a interface. To clarify my problem, here a example.
template<typename T>
class A{
virtual T getValue() = 0;
}
class B : public A<int>{
//does some things and implements getValue
}
//template definition
//T should become int by passing class B
class C{
A* aPointer;
T previousValue;
}
I've tried template template (not a typing error) syntax, explained really nice in this post. What are some uses of template template parameters in C++?. But because the type of A is determent in the definition of B it doesn't work.
How should i go about and create a template that determines T.
You can't determine the type of T directly from B, but you can from its interface. The best way of handling this would be to add a typedef of T to A.
template<typename T>
class A{
virtual T getValue() = 0;
public:
typedef T ValueType;
}
class B : public A<int>{
//does some things and implements getValue
}
template<class T>
class C {
A<typename T::ValueType>* aPointer;
typename T::ValueType previousValue;
}
Define a named type alias in class interfaces.
The standard library also does this.
template<typename T>
class A{
public:
using value_type = T;
virtual value_type getValue() = 0;
};
class B : public A<int>{
public:
using A<int>::value_type;
//does some things and implements getValue
value_type getValue() override { return 0; }
};
//template definition
//T should become int by passing class B
template<class Derived>
class C{
public:
using value_type = typename Derived::value_type;
A<value_type>* aPointer;
value_type previousValue;
};
int main()
{
C<B> c;
auto x = c.aPointer->getValue();
}
You can use a support function of which you don't even have to give a definition.
It follows a minimal, working example:
#include<type_traits>
#include<utility>
template<typename T>
class A{};
class B : public A<int>{};
template<typename T>
T a_type(const A<T> &);
template<typename T>
class C {
public:
using type = decltype(a_type(std::declval<T>()));
};
int main() {
static_assert(std::is_same<C<B>::type, int>::value, "!");
}
The good part of this approach is that you don't have to modify neither A nor B.
Suppose I have a class like so:
template<class T>
class Base{ };
Suppose I have another class like so:
template<class T, class Other>
class Derived :
public virtual Base<T>,
public virtual OtherRandomClass<Other>
{ };
Is there some way to create a template class to determine which version of Base (if any) a random class like Derived is derived from?
Here is a possible solution (working since C++11 - well, it works with C++14, but it does it with C++11 if you use Base<T> instead of auto as a return type for f):
#include<utility>
#include<type_traits>
template<class T>
class Base{ };
template<class T>
class OtherRandomClass{ };
template<class T, class Other>
class Derived :
public virtual Base<T>,
public virtual OtherRandomClass<Other>
{ };
template<typename T>
constexpr auto f(const Base<T> &b) { return b; }
template<typename T>
struct S {
using type = decltype(f(std::declval<T>()));
};
int main() {
static_assert(std::is_same<typename S<Derived<int, double>>::type, Base<int>>::value, "!");
}
It doesn't work if Derived inherits more than once from Base.
Using sfinae (something like the void_t idiom) one can even design a class that works similarly to enable_if: it has type only if T actually inherits from Base once.
It would have the following form:
template<typename T>
constexpr auto f(const Base<T> &b) { return b; }
template<typename...>
using void_t = void;
template<typename T, typename = void_t<>>
struct S { };
template<typename T>
struct S<T, void_t<decltype(f(std::declval<T>()))>> {
using type = decltype(f(std::declval<T>()));
};
This struct can be used at compile time for any template trickery you can imagine.
In both cases, S::type (if it exists) is the type of the base class from which Derived inherits, that is Base<T>.
See the static_assert in the main function of the example for further details.
#include <iostream>
#include <typeinfo>
// placeholder template
template<class SomeDerived> struct traits {};
template<class T>
class Base{ };
template<class T>
class OtherRandomClass{ };
template<class T, class Other>
class Derived :
public virtual Base<T>,
public virtual OtherRandomClass<Other>
{ };
// specialise for our class to provide introspection
template<
class T1,
class T2>
struct traits<
Derived<T1, T2>
>
{
using t1_type = T1;
using first_base_type = Base<T1>;
};
int main()
{
Derived<int, float> x;
using mytraits = traits<decltype(x)>;
std::cout << typeid(mytraits::t1_type).name() << std::endl;
std::cout << typeid(mytraits::first_base_type).name() << std::endl;
}
I am trying to implement a template class that is intended to be used both as a base for deriving and for use as a concrete class if the template parameters are right.
What I want to achieve is that if a method of the template class cannot be instantiated, but a deriving class provides an implementation, that this is OK.
But if the template can be fully instantiated that the class is valid on it's own.
Example:
// interface class
class A
{
public:
virtual void foo() = 0;
virtual ~A() {}
};
// template class
template <typename T>
class B : public A
{
public:
/* if this tenplate can be instantiated */
foo()
{
T obj;
std::cout << obj;
}
/* else
foo() = 0;
*/
};
// concrete classes
// will work on it's own
typedef B<std::string> C;
class D : public B<void>
{
// B<void>::foo won't instantiate on it's own
// so we provide help here
foo() {}
};
int main(int argc, char const *argv[])
{
A * = new C(); // all good
A * = new D(); // error: cannot instantiate B<void>::foo
return 0;
}
Is there a way to achieve such an effect?
Using SFINAE, you may do something like:
namespace detail
{
// an helper for traits
template <typename T>
decltype(T{}, std::cout << T{}, std::true_type{})
helper_has_default_constructor_and_foo(int);
template <typename T>
std::false_type helper_has_default_constructor_and_foo(...);
// the traits
template <typename T>
using has_default_constructor_and_foo = decltype(helper_has_default_constructor_and_foo<T>(0));
// genaral case (so when traits is false)
template <typename T, typename = has_default_constructor_and_foo<T>>
struct C : public A {};
// specialization when traits is true
template <typename T>
struct C<T, std::true_type> : public A
{
void foo() override { std::cout << T{}; }
};
}
And finally:
template <typename T>
class B : public detail::C<T>
{
};
live demo
You could specialize for B<void>:
// template class
template <typename T>
class B : public A
{
public:
virtual void foo()
{
T obj;
std::cout << obj;
}
};
template <>
class B<void> : public A
{
public:
virtual void foo() = 0;
};
You must specialise B<> and cannot use SFINAE (on the member foo). SFINAE only works on templates, but member function templates cannot be virtual.
There are different ways you can achieve the specialization, but the most straightforward is the simple and explicit
template<typename T>
class B : public A
{
/* ... */ // not overridden foo() by default
};
template<>
class B<WhatEver> : public A
{
virtual foo();
};
I'm writing a template <class T> array-like class A, and I want to specialize a few member functions to deal with arrays of arrays A<A<T>>.
Here is an working example that is close to what I want:
#include "stdio.h"
//primary template class
template <class T> class A {
public: void f() {printf("A<T>::f\n");}
};
//1st solution : specialization (?) of A for A<A<T>>
template <class T> class A< A<T> > {
public: void f() {printf("A<A<T>>::f\n");}
};
//2nd solution : specialization of A::f for A<A<int>>
template<> void A< A<int> >::f() {
printf("A<A<int>>::f\n");
}
int main(void) {
A<int> A_int;
A< A<int> > A_A_int;
A< A<double> > A_A_double;
A_int.f(); // ok : prints A<T>::f
A_A_int.f(); // ok : prints A<A<int>>::f
A_A_double.f(); // ok : prints A<A<T>>::f
return 0;
}
The problem with 1st solution is that I have to duplicate a lot of member functions from the primary template class
I tried to derive from the primary class but
template <class T> class A< A<T> > : public A< A<T> >
makes no sense
The problem with 2nd solution is that I have to duplicate the specialization for every possible types, and that defeats the purpose of template classes.
Since it is possible to define template<> void A< A<int> >::f(), it seems one should be able to "templatize" this specialization for any type. I tried :
template <class T> template<> void A< A<T> >::f()
template <template <class T> > void A< A<T> >::f()
template <template <> class T> void A< A<T> >::f()
and other absurd syntaxes...
So... Can I templatize the specialization template<> void A< A<int> >::f() not just for int but for any type T ?
Thanks in advance,
Best regards,
One possible way:
#include <cstdio>
// forward declaration
template<typename>
class A;
template<typename>
class A_Base {
// general case
public: void f() { printf("A<T>::f\n"); }
};
// partial specialization for any A
template<typename T>
class A_Base< A<T> > {
// special stuff
public: void f() { printf("A<A<T>>::f\n"); }
};
template<typename T>
class A : private A_Base<T> { // private inheritance, we're not modeling IS-A
public:
using A_Base<T>::f; // make f accesible
// all the other stuff that doesn't need to change
};
int main()
{
A<int> a1;
A<A<int>> a2;
a1.f(); // A<T>::f
a2.f(); // A<A<T>>::f
}
This way you put only the functions that need to behave differently in the base class. You can of course make it vice-versa - you put common code in the base class and specialize a derived class where you also define f.