Member function syntax in class template specialization - c++

I have a class template, let's call it A, which has a member function abc():
template <typename T>
class A{
public:
T value;
void abc();
};
I can implement the member function abc() outside the class declaration, using the following syntax:
template <typename T>
void A<T>::abc()
{
value++;
}
What I want to do is to create a template specialization for this class, let's say int.
template <>
class A<int>{
public:
int value;
void abc();
};
The question is: what is the correct syntax to implement abc() for the specialized class?
I tried using the following syntax:
template <>
void A<int>::abc()
{
value += 2;
}
However this doesn't compile.

void A<int>::abc()
{
value += 2;
}
since A<int> is explicit specialisation of A<T>.
http://liveworkspace.org/code/982c66b2cbfdb56305180914266831d1
n3337 14.7.3/5
Members of an explicitly specialized class template are
defined in the same manner as members of normal classes, and not using the template<> syntax.
[ Example:
template<class T> struct A {
struct B { };
template<class U> struct C { };
};
template<> struct A<int> {
void f(int);
};
void h() {
A<int> a;
a.f(16);
}
// A<int>::f must be defined somewhere
// template<> not used for a member of an
// explicitly specialized class template
void A<int>::f(int) { /∗ ... ∗/ }

Remove the template<>:
void A<int>::abc()
{
value += 2;
}

Related

Specialise only parts of template class while keeping the rest generic

Assuming the following class:
template <typename T>
class Test {
public:
void do_something1();
...
void do_something100(); // basically many functions already defined
}
How can I add another function to a specialisation of the class while not rewriting all possibly 100 functions that are already templated?
template<>
class Test<int> {
public:
void do_something_else();
}
...
int main() {
auto x = Test<int>();
x.do_something5(); // should be still valid, would call
// Test<T>::do_something5() with T being int
x.do_something_else(); // valid because declared in specialisation
...
}
Right now, if the Test<int> specialisation is left as in the example above, it would only contain do_something_else(), without do_something1...100().
Solution
Based on the accepted answer, using the given example, I did the following:
namespace parent {
template <typename T>
class Test {
public:
void do_something1();
...
void do_something100();
}
}
template <typename T>
class Test : public parent::Test<T> {
using parent::Test<T>::Test; // inherit constructors
}
template <>
class Test<int> : public parent::Test<int> {
using parent::Test<int>::Test;
public:
void do_something_else();
}
You can create a common base class, and make both the primary template and specialization deriving from it.
Or you can make do_something_else function template and only works with int (then don't need using specialization).
template <typename T>
class Test {
public:
void do_something1();
...
void do_something100(); // basically many functions already defined
template <typename X = T>
std::enable_if_t<std::is_same_v<X, int> && std::is_same_v<X, T>> do_something_else();
};
Or since C++20 we can use Constraints as #aschepler suggested.
template <typename T>
class Test {
public:
void do_something1();
...
void do_something100(); // basically many functions already defined
void do_something_else() requires std::is_same_v<T, int>;
};

Is it possible to refer to a user-defined conversion template in a using declaration?

In a class B inheriting from class A, it's possible to use a using declaration to bring members of A into B, even templates, like this:
struct A {
template <typename T>
void foo();
};
struct B : private A {
using A::foo;
};
But can it be done for conversion templates?
struct A {
template <typename T>
operator T();
};
struct B : private A {
using A::operator /* ??? */;
};
There seems to be no way of referring to the template by name, but I would love to be proven wrong or get some clarification.
As a workaround, you can cast to the base class and convert it explicitly:
struct A {
template <typename T>
operator T() {
return T{};
}
};
struct B : private A {
template <class T>
operator T() {
return static_cast<T>(static_cast<A&>(*this));
}
};
int main() {
A a;
B b;
int i_a = a;
int i_b = b;
}

Conditional compilation and template

Suppose, I have a code:
template <typename T>
class C {
public:
T f() { return m_result; }
void todo() { m_result = doit<T>(); }
private:
T m_result;
};
If T is void, I want to return void and have no m_result at all.
But, the compiler does not allow instantiate a void type.
One of decision is to create a specialization.
template <> class C<void> { /* ... */ }
But I don't what to support the almost identical code.
How can I don't instantiate m_result?
I can use C++17. Thanks!
You could place the data in a base class, then use if constexpr:
template<class T>
struct C_data{
T m_result;
};
template<>
struct C_data<void>{
};
template<class T>
class C: C_data<T>
{
static constexpr auto is_void = std::is_same_v<T,void>;
public:
auto f(){
if constexpr(is_void)
return this->m_result;
else
return;
}
void todo(){
if constexpr(is_void)
this->m_result = doit<T>();
else
doit<T>();
}
};
But it can be argued that a the specialization of the class C is cleaner since all member of a template class should depend on all the template parameter (otherwise you should split your class in order to avoid code bloat).
So I would prefer to fully specialize C, and make part of the class C that are independent of T, a base class of C:
class C_base{
//any thing that is independent of T;
};
template<class T>
class C: public C_base{
//any thing that depend on T
};
template<>
class C<void>: public C_base{
//any thing that depend on T;
};
You could also specialize member funtion by member function, but I find it less clean.
You will find this last code structure in almost all headers of standard library implementations.
This works for me:
#include <type_traits>
template <typename T> T doit() { return T{}; }
template <typename T> struct result_policy { T m_result; };
template <> struct result_policy<void> { };
template <typename T>
class C : private result_policy<T> {
public:
T f(){
if constexpr (!std::is_void_v<T>)
return result_policy<T>::m_result;
}
void todo() {
if constexpr(!std::is_void_v<T>)
result_policy<T>::m_result = doit<T>();
}
};
int main() {
C<int> ci;
ci.todo();
int i = ci.f();
C<void> cv;
cv.todo();
cv.f();
}
I used if constexpr from C++17 to work with m_result and stored m_result into policy struct only for non-void types due to partial template specialization.
If you can use C++17, then try with if constexpr, std::is_same_v<> and std::conditional_t<>:
#include <type_traits>
// auxiliary variable template for checking against void type in a more readable way
template<typename T>
constexpr bool is_void_v = std::is_same_v<T, void>;
// auxiliary alias template for determining the type of the data member
// in order to prevent the compiler from creating member of type "void"
// so if T = void --> data member type as "int"
template<typename T>
using member_type_t = std::conditional_t<!is_void_v<T>, T, int>;
template <typename T>
class C{
public:
T f(){ return (T)m_result; } // no problem if T = void
void todo() {
if constexpr(!is_void_v<T>)
m_result = doit<T>();
else
doit<T>();
}
private:
member_type_t<T> m_result;
};
Actually, as of C++17 there is already a std::is_void_v<> variable template with type_traits.

Specialized template classes with common functions

Is it possible to specialize a few functions for a template class without specializing the whole thing?
For example:
template <typename T>
struct A {
int foo();
};
template <typename T>
int A<T>::foo() { return 1;}
template <>
struct A<int> {
int bar() { return 2; };
};
main() {
A<int> a;
a.foo(); //1
a.bar(); //2
A<double> b;
b.foo(); //1
b.bar(); // ERROR
}
Or something similar?
No. But there is a way around it.
Hand off the logic to a free function template specialisation from within the template class method.
template<class T>
int delegated_foo() {
return 1;
}
// now specialise
template<>
int delegated_foo<int>() {
return 2;
}
template <typename T>
struct A {
int foo() {
return delegated_foo<T>();
}
};
To answer the comment - if you want to partially specialise a class, you can delegate common logic in to a template base class.
template<class T>
struct a_common {
void common_function() {
// define here. Compiler will generate 1 for each T
}
};
template<class T>
struct A : public a_common<T>
{
int something_i_might_specialise();
};

C++ class template or pure virtual

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();
};