I need conditional using member declaration.
template <bool> struct B;
template <> struct B<true> { void foo(); };
template <> struct B<false> { };
template <typename T>
struct A : public B<is_default_constructible<T>::value> {
using B<is_default_constructible<T>::value>::foo();
void foo(int) {}
};
This obviously doesn't work, because B<bool>::foo is not defined
in half the cases. How can I achieve that? To have B<>::foo()
visible in A<T> scope beside foo(int)?
Thanks for help
This is my solution. I'm sure it's won't be the best but it gets the job done.
struct A {
void foo(int) {}
};
struct A should contain methods you want defined in both cases.
template <bool> struct B;
template <> struct B<false> : A {};
template <> struct B<true> : A {
using A::foo;
void foo() {}
};
In case of B<false>, only void foo(int) is defined. In case of B<true>, both void foo(int) and void foo() are defined.
template <typename T>
struct C : public B<is_default_constructible<T>::value> {};
Now I don't have to worry about B<is_default_constructible<T>::value>::foo() not being defined in certain cases.
class D { D() = delete; };
int main()
{
C<int> c1;
c1.foo(1234);
c1.foo();
// both methods are defined for C<int>
C<D> c2;
c2.foo(1234);
// c2.foo(); // undefined method
return 0;
}
Use specialization.
enable_if can't be used for that. You need to specialize struct A too.
#include <type_traits>
template <bool> struct B;
template <> struct B<true> { void foo(); };
template <> struct B<false> { };
template <typename T, bool default_constructible = std::is_default_constructible<T>::value>
struct A : public B<default_constructible> {
using B<default_constructible>::foo;
void foo(int) {}
};
template<typename T>
struct A<T, false> : public B<false> {
void foo(int) {}
};
Avoiding duplicate code for foo(int)
If foo(int) will have the same functionality in both cases, you may want to derive it from another base struct:
#include <type_traits>
template <bool> struct B;
template <> struct B<true> { void foo(); };
template <> struct B<false> { };
template<typename T>
struct C {
void foo(int) {}
};
template <typename T, bool default_constructible = std::is_default_constructible<T>::value>
struct A : public B<default_constructible>, public C<T> {
using B<default_constructible>::foo;
using C<T>::foo;
};
template<typename T>
struct A<T, false> : public B<false>, public C<T> {
using C<T>::foo;
};
Removing that ugly bool
Finally, to remove that bool from struct A's template parameters, you may want to forward the responsibility of selecting the overloads of foo to a base class. This also has the advantage of not duplicating code for other struct A's members you may want to add.
#include <type_traits>
template <bool> struct B;
template <> struct B<true> { void foo(); };
template <> struct B<false> { };
template<typename T>
struct C {
void foo(int) {}
};
template <typename T, bool default_constructible = std::is_default_constructible<T>::value>
struct base_A : public B<default_constructible>, public C<T> {
using B<default_constructible>::foo;
using C<T>::foo;
};
template<typename T>
struct base_A<T, false> : public B<false>, public C<T> {
using C<T>::foo;
};
template <typename T>
struct A : public base_A<T> {
// Other members.
};
Related
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
How would you go about filling-in a method if a base class doesn't provide it. I'd like to reuse the base class method if it is provided.
E.g.:
#include <iostream>
struct Base0 { };
struct Base1 { void m() { std::cout<<"Base1\n"; } };
template<typename T>
struct Derived : public T {
//if T doesn't provide m, define it here, otherwise reuse the base class method
void m(){ /*? std::cout<<"Derived\n"; ?*/ }
};
int main(){
Derived<Base0> d0;
d0.m(); //should print "Derived"
Derived<Base1> d1;
d1.m(); //should print "Base1"
}
With SFINAE, you may do
template<typename T>
struct Derived : public T {
private:
template <typename U = T>
auto m_impl(int) -> decltype(std::declval<U&>().m()){ this->U::m(); }
template <typename U = T>
void m_impl(... ) { std::cout<<"Derived\n"; }
public:
void m() { m_impl(0); }
};
Demo
In order to be general, you should define the function anyway under a different signature:
template<typename T>
struct Derived : public T
{
auto m(std::false_type) { std::cout<<"Derived\n"; }
};
Then you can use the methods given in this thread in order to check whether the base class has the function m():
template <typename...>
using void_t = void;
template <typename T, template <typename> class D, typename = void>
struct detect : std::false_type {};
template <typename T, template <typename> class D>
struct detect<T, D, void_t<D<T>>> : std::true_type {};
template <typename T>
using has_m = decltype(std::declval<T>().m());
Finally, you can use that as
template<typename T>
struct Derived : public T
{
auto m(std::true_type) { return T::m(); }
auto m(std::false_type) { std::cout<<"Derived\n"; }
auto m() { return m(detect</* const */ T, has_m>{}); }
^^^^^^^^^^
//if m() is const
};
DEMO
As Aslay Berby already said this is probably not the way that you would like to go. If you want to implement something like traits or policy-based design, the following code might be what you are looking for. In fact such designs are used quite commonly and have also idiomatic value.
#include <iostream>
using namespace std;
struct StandardTraits {void foo() {cout << "standard" << endl;}};
struct Traits1 {void foo() {cout << "traits1" << endl;}};
struct Traits2 {void foo() {cout << "traits2"<< endl;}};
template<typename T = StandardTraits>
class SomeClass
{
public:
typedef T Traits;
void useTraits() {traits.foo();}
private:
Traits traits;
};
int main() {
SomeClass<> x;
SomeClass<Traits1> y;
SomeClass<Traits2> z;
x.useTraits();
y.useTraits();
z.useTraits();
return 0;
}
// output:
// standard
// traits1
// traits2
See also: https://en.wikipedia.org/wiki/Policy-based_design
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 want to specialize a constructor of a class template. This doesn't work:
template<typename T>
struct One {};
template<typename T>
struct Two {};
template<template<typename> class T, template<typename> class U>
struct Three : public T<Three<T, U>>, public U<Three<T, U>> {};
template<typename T> struct Four;
template<typename T>
struct Four
{
Four();
};
template<template<typename> class T, template<typename> class U>
Four<Three<T, U>>::Four() {}
int main(int argc, char *argv[])
{
Four<Three<One, Two> > obj;
}
but changing the class template definition to this works:
template<typename T> struct Four;
template<template<typename> class T, template<typename> class U>
struct Four<Three<T, U>>
{
Four();
};
template<template<typename> class T, template<typename> class U>
Four<Three<T, U>>::Four() {}
This seems like I'm specializing the entire class template. However I want to specialize only the constructor as in the code above - the one that doesn't work. Why can't I specialize the constructor of Four for just Three (I'm not changing the signature of the ctor of the class template)?
You can't. You must specialize the whole class. But.. you can use inheritance as a work around:
#include <iostream>
class something {};
template <typename T> class hidden_base {
public: hidden_base() {a = 1;}
protected: int a;
};
template<> class hidden_base<something> {
public: hidden_base() {a = 2;}
protected: int a;
};
template <typename T>
class your_class : public hidden_base<T> {
public:
void lots();
void of();
void other();
void member();
void functions();
void here();
void show_a() {std::cout << hidden_base<T>::a << std::endl;}
};
int main() {
your_class<long>().show_a();
your_class<int>().show_a();
your_class<something>().show_a();
}
This will print:
1
1
2
To have a sort of duck typing, I do
template<bool b>
struct A{
static template<typename V> f1(V*, [other params]);
static template<typename V> f2(V*, [other params]);
};
template<> template<typename T>
void A<false>::f1(V*, [other params]){}
template<> template<typename T>
void A<true>::f1(V*, [other params]){
...some code...
}
template<int flags>
struct V{
void f(){
A<flags&Some compile time conditions>::f1 (this,[params]);
A<flags&Some compile time conditions>::f2 (this,[params]);
}
};
Do you think there is a more elegant solution, which is not Template class, function specialization
(I do not want to add an extra param to the functions)
I would like to do something like
template<int X> struct C{
void f(){std::cout<<"C::f"<<std::endl;};
};
template<> struct C<0>{
};
template<int X> struct D{
C<X> c;
template<bool b>
void f();
void g(){
f<X!=0>();
}
};
template<>
template<int X>
void D<X>::f<true>{
c.f();
};
template<int X>
template<>
void D<X>::f<false>{};
int main(){
D<3> ch;
ch.g();
D<0> cn;
cn.g();
}
but this is not valid code, and I get error: template-id âfâ used as a declarator.
Is there a way to specialize a template function by the value of its non-type template parameter?
template<>
template<int X>
void D<X>::f<true>(){
c.f();
};
template<int X>
template<>
void D<X>::f<false>(){};
That is illegal (all attempts are). When you specialize a member function template, it's enclosing class has to be specialized as well.
However, you can overcome that easily by wrapping your function inside a templated struct that would take its template arguments. Something like
template <int X, bool B>
struct DXF;
template <int X>
struct DXF<X, true>
{
static void f() { // B is true!
}
};
template <int X>
struct DXF<X, false>
{
static void f() { // B is false!
}
};
and call it with DXF<X, (X!=0)>::f().
However, it seems that you just want to specialize for X==0. In that case, you can just specialize:
template <>
void D<0>::f() {}
Note that f in that case is not a member template.
Another option you can go for is overloading. You could wrap your int in a parameter list of some template, like this:
template<int X> struct D{
C<X> c;
void f(std::true_type*) { ... true code ... }
void f(std::false_type_*) { ... false code ... }
void g(){
f((std::integral_constant<bool, X!=0>*)0);
}
Note that true_type and false_type are just typedefs of std::integral_constant<bool, true> and false, resp.