c++ template tricky partial specialization const+template member - c++

I have template struct declared as:
template <bool sel_c>
struct A
{
A(){/*...*/}
enum{
is_straight = sel_c
};
typedef A<sel_c> this_t;
typedef A<!sel_c> oposit_t;
A(const this_t& copy){/*...*/}
A(const oposit_t& copy){/*...*/}
~A(); //will be specialized latter for true/false
template <class T> //this is my pain !
void print(T& t);
};
How can I declare specializations of both print methods?
I have already tried following (with error: error C2244: 'A::print' : unable to match function definition to an existing declaration )
template <class T>
void A<false>::print(T& t)
{
/*...*/
}
And following (with error that no copy constructor declared early above):
template <> struct A<false>
{
~A()
{
/*...*/
}
template <class T>
void print(T& t)
{
/*...*/
}
};

template<>
template< class T >
void A<false>::print( T& t ) {}

I don't see any problem with your second solution, the following compiles just fine with g++:
template <bool sel_c>
struct A
{
A(){/*...*/}
enum{
is_straight = sel_c
};
typedef A<sel_c> this_t;
typedef A<!sel_c> oposit_t;
A(const this_t& copy){/*...*/}
A(const oposit_t& copy){/*...*/}
~A(); //will be specialized latter for true/false
template <class T> //this is my pain !
void print(T& t);
};
template <>
struct A<false>
{
~A(){};
template <class T>
void print(T& t) {}
};
template <>
struct A<true>
{
~A(){};
template <class T>
void print(T& t) {}
};
int main(int argc, char** argv)
{
A<false> a1;
A<true> a2;
}
EDIT: this is incomplete, see comments

Related

Template argument deduction failed with typedef?

Considering the following couple of classes:
template <typename T1, typename T2>
class A{
public:
// ...
};
template<typename _T>
struct alias { typedef A<int,_T> intA; };
class B{
public:
// ...
template <typename _T> B& operator=(const typename alias<_T>::intA& _arg) { };
};
When I try to assign an object of class A<int,int> to an object of class B, I get the following compilation error:
template argument deduction/substitution failed: couldn't deduce template parameter ‘_T’
Is there an alternative way to use something of a typedef as the input argument to B::operator=()??
templated using might fix the issue
template <typename T1, typename T2>
class A{
public:
// ...
};
template<typename _T>
using alias = A<int,_T>;
class B{
public:
// ...
template <typename _T> B& operator=(const alias<_T>& ) { return *this; };
};
void f()
{
B b;
A<int, int> a;
b = a;
}
The problem is that intA is a dependant name. Templates cannot be deduced from dependant names. See for example: Dependent Types: Template argument deduction failed.
You are also missing the typename keyword.
You can either explicitly specify the type for the operator:
template <typename T1, typename T2>
struct A{ };
template<typename _T>
struct alias { typedef A<int,_T> intA; };
struct B
{
template <typename T> B& operator=(const typename alias<T>::intA& _arg) { };
};
int main()
{
A<int,int> a;
B b;
b.operator=<int>(a);
return 0;
}
or you can have a specific, non-dependant-name parameter using a templated alias (with or without a function):
template <typename T1, typename T2>
struct A{ };
template<class T>
using alias_int = A<int, T>;
struct alias
{
template<class T>
using intA = A<int, T>;
};
struct B
{
template <typename T> B& operator=(const alias_int<T>& _arg) { };
};
struct C
{
template <typename T> C& operator=(const alias::intA<T>& _arg) { };
};
int main()
{
A<int,int> a;
B b;
C c;
b = a;
c = a;
return 0;
}
I'm getting a different error (using g++ 5.4):
need ‘typename’ before ‘alias<_T>::intA’ because ‘alias<_T>’ is a dependent scope
and true enough the following compiles for me:
template <typename T1, typename T2>
class A{
public:
// ...
};
template<typename _T>
struct alias { typedef A<int,_T> intA; };
class B{
public:
// ...
template <typename _T> B& operator=(const typename alias<_T>::intA& _arg) { };
};
I think the reason is that alias<_T>::intA isn't an actual type but a templated typename.

Trying to put partial in different header

I have the following program working fine. But once I get rid of the forward declaration of the primary specialization in bar.h. I got compilation error saying the specialization is not a class template. Why?
bar.h:
template<typename T>
struct Bar{
void bar()
{
std::cout<< "bar" << std::endl;
};
};
//template<typename T> // Looks like I need to forward declare this in order to have it compile and work, why?
//struct IsBar;
template<typename T>
struct IsBar<Bar<T>> {
static const bool value = true;
};
main.cpp:
#include "bar.h"
struct Raw{
};
template<typename T>
struct IsBar{
static const bool value = false;
};
template<typename Obj, bool>
struct function{
static void callbar(Obj obj){
obj.bar();
};
};
template<typename Obj>
struct function<Obj, false>{
static void callbar(Obj obj){
std::cout<< "no bar()" << std::endl;
};
};
int main()
{
typedef Bar<Raw> Obj;
Obj obj;
function<Obj, IsBar<Obj>::value> f;
f.callbar(obj);
return 0;
}
This is because
template<typename T>
struct IsBar<Bar<T>> {
static const bool value = true;
};
is a template specialization of the template IsBar<U> for U=Bar<T>. In order to specialize a template, you must first declare the general un-specialized template.
Moreover, for this to work properly (for example in SFINAE), you want the general version to contain the value=false:
template<typename T>
struct IsBar
: std::integral_constant<bool,false>
{};
template<typename T>
struct IsBar<Bar<T>>
: std::integral_constant<bool,true>
{};
As this functionality is closely related to struct Bar<>, it should be defined within the same header file as struct Bar<>, i.e. bar.h in your case.

Meta-iteration over variadic templates arguments

I would like to generalize the following pattern:
template<class A1, class A2, class A3>
class Foo {
protected:
template<class T>
void foo(const T& t) {...do stuff...}
public:
void bar(const A1& a) { foo(a); }
void bar(const A2& a) { foo(a); }
void bar(const A3& a) { foo(a); }
};
The above approach does not scale with a number of increasing arguments. So, I'd like to do:
template<class As...>
class Foo {
protected:
template<class T>
void foo(const t& a) {...do stuff...}
public:
for each type A in As declare:
void bar(const A& a) { foo(a); }
};
Is there a way to do it?
another approach could be to have a check in bar to test if the type is in the sequence, else barf with a useful error message, this avoid any inheritance tricks..
#include <iostream>
struct E {};
struct F {};
template <class... As>
class Foo
{
template <typename U>
static constexpr bool contains() {
return false;
}
template <typename U, typename B, typename ...S>
static constexpr bool contains() {
return (std::is_same<U, B>::value)? true : contains<U, S...>();
}
protected:
template <class T>
void foo(const T& a) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
public:
template <class T>
void bar(const T& a) {
static_assert(contains<T, As...>(), "Type does not exist");
foo(a);
}
};
int main()
{
Foo<E, F, E, F> f;
f.bar(F{});
f.bar(E{});
f.bar(1); // will hit static_assert
}
In case you don't actually need the bars and instead just need to constrain foo - we can use SFINAE to allow a call to it only with a type convertible to one of the As:
template <class... As>
class Foo {
public:
template <class T,
class = std::enable_if_t<any<std::is_convertible<T, As>::value...>::value>>
void foo(T const&) { ... }
};
Where we can implement any with something like the bool_pack trick:
template <bool... b> struct bool_pack { };
template <bool... b>
using any = std::integral_constant<bool,
!std::is_same<bool_pack<b..., false>, bool_pack<false, b...>>::value>;
template <class CRTP, class A, class... As>
struct FooBar
{
void bar(const A& a)
{
static_cast<CRTP*>(this)->foo(a);
}
};
template <class CRTP, class A, class B, class... As>
struct FooBar<CRTP, A, B, As...> : FooBar<CRTP, B, As...>
{
using FooBar<CRTP, B, As...>::bar;
void bar(const A& a)
{
static_cast<CRTP*>(this)->foo(a);
}
};
template <class... As>
class Foo : FooBar<Foo<As...>, As...>
{
template <class, class, class...>
friend struct FooBar;
protected:
template <class T>
void foo(const T& a) { }
public:
using FooBar<Foo, As...>::bar;
};
DEMO
template <class A, class... As>
class Foo : public Foo<As...>
{
protected:
using Foo<As...>::foo;
public:
using Foo<As...>::bar;
void bar(const A& a) { foo(a); }
};
template <class A>
class Foo<A>
{
protected:
template <class T>
void foo(const T& t) { }
public:
void bar(const A& a) { foo(a); }
};
In a similar vain to Piotr Skotnicki's answer, this uses inheritance to build up a class with bar overloads for all of the template arguments. It's a bit cleaner though, with only one class template plus a partial specialization.
template<class A, class Foo_t>
class bar_t {
public:
void bar(const A &a) { Foo_t::foo(a); }
};
template<class ...As>
class Foo : bar_t<As, Foo<As...> >... {
protected:
template<class T>
void foo(const T& a) { /* do stuff */ }
};

Using member declaration with enable_if?

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.
};

C++ specializing a member function

I need to make a class with a generic data member, that works something like istream. For all types it should be able to store data that it recieves by the << operator. I want it to work for single variables unless the class is created for char, where it should work for C strings.
template <typename T>
class foo<C>{
T* data;
public:
void operator << (T t);
};
template <typename T>
class foo<char>: public foo<T>{
public:
void operator << (char* str)
};
This is how I tried to solve it, but I get an erro saying: explicit specialization is using partial specialization syntax.
Is this what you intended?
template <typename T>
class foo
{
T* data;
public:
void operator<<(T t);
};
template <>
class foo<char>
{
public:
void operator<<(char* str);
};
If you meant to inherit behavior, you'll need something like this:
template <typename T>
class foo_impl
{
T* data;
public:
void operator<<(T t);
};
template <typename T>
class foo : public foo_impl<T>
{
};
template <>
class foo<char> : public foo_impl<char>
{
public:
void operator<<(char* str);
};
(or, even simpler by eliminating unneeded occurrences of public)
template <typename T>
class foo_impl
{
T* data;
public:
void operator<<(T t);
};
template <typename T>
struct foo : foo_impl<T>
{
};
template <>
struct foo<char> : foo_impl<char>
{
void operator<<(char* str);
};
And I would suggest some const-correctness:
template <typename T>
class foo_impl
{
T* data;
public:
void operator<<(const T& t);
};
template <typename T>
struct foo : foo_impl<T>
{
};
template <>
struct foo<char> : foo_impl<char>
{
void operator<<(const char* str);
};
You cannot specify a template type within the class declaration.
template <typename T>
class foo{
T* data;
public:
void operator << (T t);
};
Try this. It may also help to read the cplusplus.com documentation on templates. http://www.cplusplus.com/doc/tutorial/templates/