C++ Syntax For Explicit Specialization of a Template Function in a Template Class

C++ syntax for explicit specialization of a template function in a template class?

You can't specialize a member function without explicitly specializing the containing class.

What you can do however is forward calls to a member function of a partially specialized type:

template<class T, class Tag>
struct helper {
static void f(T);
};

template<class T>
struct helper<T, tag1> {
static void f(T) {}
};

template<class T>
struct C {
// ...
template<class Tag>
void foo(T t) {
helper<T, Tag>::f(t);
}
};

C++ template function explicit specialization with multiple template types

template<bool B, typename T>
void foo(T const&)
{
static_assert(false, "not implemented");
}

template<bool B>
void foo(short)
{
printf("it's a short!\n");
}

However, this is not really specialisation, but overloading, which is completely appropriate. In fact, you could omit the general case.

How do I define an explicit specialization of a template member function in .cpp file

I'm not sure, but I think you're trying to do this.

In Foo.h

struct Color {};

class Foo
{
public:
template<typename T> int add(T b);
};

// declare, but do not implement, specialization
template<>
int Foo::add<Color>(Color c);

// general implementation
template<typename T>
int Foo::add(T b)
{
return 0;
}

In Foo.cpp

#include "Foo.h"

// explicitly implement
template<>
int Foo::add<Color>(Color b)
{
return 42;
}

Finally, main.cpp

#include "Foo.h"

int main()
{
Foo f;
std::cout << f.add(Color()) << '\n';
}

Output

42

C++ specialization of template function inside template class

So, I'm taking a different approach to answering your question. I'm going to start from something that sort of does what you want, and works. And then maybe we can figure out how to permute it into something closer to what you really want:

#include <string>
#include <iostream>

int getIntThing(const ::std::string ¶m);

template <typename returnT>
returnT getThingFree(const ::std::string ¶m);

template <>
int getThingFree<int>(const ::std::string ¶m)
{
return getIntThing(param);
}

// More specialized definitions of getAThing() for other types/classes
// go here...

template <class c1> class X {
public:
template<typename returnT> returnT getAThing(std::string param);
static std::string getName();
private:
c1 theData;
};

// This works ok...
template <class c1> std::string X<c1>::getName() {
return c1::getName();
}

// This also works, but it would be nice if I could explicitly specialize
// this instead of having to explicitly specialize getThingFree.
template <class c1>
template <class RT>
RT X<c1>::getAThing(std::string param) {
// Some function that crunches on param and returns an RT.
// Gosh, wouldn't it be nice if I didn't have to redirect through
// this free function?
return getThingFree<RT>(param);
}

class Y {
public:
static std::string getName() { return "Y"; }
};

int main(int argc, char* argv[])
{
using ::std::cout;
X<Y> tester;
int anIntThing = tester.getAThing<int>(std::string("param"));
cout << "Name: " << tester.getName() << '\n';
cout << "An int thing: " << anIntThing << '\n';
}

Here is another idea that sort of works, and isn't exactly what you want, but is closer. I think you've thought of it yourself. It's also rather ugly in the way it uses type deduction.

#include <string>
#include <iostream>

template <class c1> class X;

int getIntThing(const ::std::string ¶m)
{
return param.size();
}

// You can partially specialize this, but only for the class, or the
// class and return type. You cannot partially specialize this for
// just the return type. OTOH, specializations will be able to access
// private or protected members of X<c1> as this class is declared a
// friend.
template <class c1>
class friendlyGetThing {
public:
template <typename return_t>
static return_t getThing(X<c1> &xthis, const ::std::string ¶m,
return_t *);
};

// This can be partially specialized on either class, return type, or
// both, but it cannot be declared a friend, so will have no access to
// private or protected members of X<c1>.
template <class c1, typename return_t>
class getThingFunctor {
public:
typedef return_t r_t;

return_t operator()(X<c1> &xthis, const ::std::string ¶m) {
return_t *fred = 0;
return friendlyGetThing<c1>::getThing(xthis, param, fred);
}
};

template <class c1> class X {
public:
friend class friendlyGetThing<c1>;

template<typename returnT> returnT getAThing(std::string param) {
return getThingFunctor<c1, returnT>()(*this, param);
}
static std::string getName();
private:
c1 theData;
};

// This works ok...
template <class c1> std::string X<c1>::getName() {
return c1::getName();
}

class Y {
public:
static std::string getName() { return "Y"; }
};

template <class c1>
class getThingFunctor<c1, int> {
public:
int operator()(X<c1> &xthis, const ::std::string ¶m) {
return getIntThing(param);
}
};

// More specialized definitions of getAThingFunctor for other types/classes
// go here...

int main(int argc, char* argv[])
{
using ::std::cout;
X<Y> tester;
int anIntThing = tester.getAThing<int>(std::string("param"));
cout << "Name: " << tester.getName() << '\n';
cout << "An int thing: " << anIntThing << '\n';
}

I would recommend declaring getThingFunctor and friendlyGetThing in a semi-private utility namespace.

Allow Only Explicit Specialization of Template Class

There are a few ways how you could accomplish this.

1. Explicitly list the acceptable enums

One way would be to explicitly list the acceptable enums in your static_assert:

godbolt

#include <type_traits>

template<class T, class... Other>
constexpr bool is_same_one_of = (std::is_same_v<T, Other> || ...);

enum Enum1 {};
enum Enum2 {};
enum Enum3 {};

template<class T>
class kvEnumHelper {
static_assert(
is_same_one_of<T, Enum1, Enum2 /* , ... more enum types ... */>,
"T must be either Enum1 or Enum2"
);

/* ... actual implementation ... */
};


kvEnumHelper<Enum1> foo1; // ok
kvEnumHelper<Enum2> foo2; // ok
kvEnumHelper<Enum3> foo3; // compile error


2. Inherit implementation

Another option would be to move the actual implementation into a separate class and only make the specializations inherit from the implementation class.

godbolt

#include <type_traits> 

enum Enum1 {};
enum Enum2 {};
enum Enum3 {};

template<class T>
class kvEnumHelper {
static_assert(
!std::is_same_v<T, T>, // always false, but only when actually instanciated
"Enum Class is not supported"
);
};

template<class TEnum>
class kvEnumHelperImpl {
/* ... actual implementation ... */
};

template<> class kvEnumHelper<Enum1> : public kvEnumHelperImpl<Enum1> {};
template<> class kvEnumHelper<Enum2> : public kvEnumHelperImpl<Enum2> {};


kvEnumHelper<Enum1> foo1; // ok
kvEnumHelper<Enum2> foo2; // ok
kvEnumHelper<Enum3> foo3; // compile error


3. Using an additional trait

Yet another alternative would be to use a trait that can specialized for the enum types you would want to be usable with kvEnumHelper.

godbolt

template <class T>
constexpr bool allow_enum_helper = false;

enum Enum1 {};
enum Enum2 {};
enum Enum3 {};

template<class T>
class kvEnumHelper {
static_assert(
allow_enum_helper<T>,
"Enum Class is not supported"
);

/* ... actual implementation ... */
};

template<>
constexpr bool allow_enum_helper<Enum1> = true;
template<>
constexpr bool allow_enum_helper<Enum2> = true;


kvEnumHelper<Enum1> foo1; // ok
kvEnumHelper<Enum2> foo2; // ok
kvEnumHelper<Enum3> foo3; // compile error

If you already have a function like getEnumFromString that is deleted and has specializations for the allowable enum types you could use that to detect if kvEnumHelper<T> should be allowed by detecting if the function is deleted or not.

godbolt

#include <string>

enum Enum1 {};
enum Enum2 {};
enum Enum3 {};

template<typename T>
T getEnumFromString(const std::string& in_string) = delete; // only allow templates we define (catches them at compile time)
template<> Enum1 getEnumFromString(const std::string& in_string);
template<> Enum2 getEnumFromString(const std::string& in_string);

template<class T>
constexpr bool allow_enum_helper = requires { getEnumFromString<T>(std::string{}); };


template<class T>
class kvEnumHelper {
static_assert(
allow_enum_helper<T>,
"Enum Class is not supported"
);

/* ... actual implementation ... */
};

kvEnumHelper<Enum1> foo1; // ok
kvEnumHelper<Enum2> foo2; // ok
kvEnumHelper<Enum3> foo3; // compile error

Syntax for explicit template specializations

C++14 standard §14.7(3) has

An explicit specialization may be declared for a function template, a class template, a member of a class template or a member template. An explicit specialization declaration is introduced by template<>. In an explicit specialization declaration for a class template, a member of a class template or a class member template, the name of the class that is explicitly specialized shall be a simple-template-id. In the explicit specialization declaration for a function template or a member function template, the name of the function or member function explicitly specialized may be a template-id.

And then demonstrates

template<class U> void g(U) { }
template<> void g(char) { } //specialize for U == char
// U is deduced from the parameter type

And then we have §14.7.3(10)

A trailing template-argument can be left unspecified in the template-id naming an explicit function template specialization provided it can be deduced from the function argument type. [ Example:

template<class T> class Array { / ... / };
template<class T> void sort(Array<T>& v);

// explicit specialization for sort(Array<int>&)
// with deduced template-argument of type int
template<> void sort(Array<int>&);

—end example ]

Is This The True Way To Implement Explicit Template Specialization Of Template Function In C++20

At very first: You are re-inventing the wheel, there's already std::max_element doing nearly (returning an iterator to, not the element itself) the same!

Then to specialise a template you first need a base template and then the specialisation, for instance:

// the base template:
template <typename T>
void demo (T const& t)
{
// do something with T
}

//the specialisation:
template<>
void demo<std::string>(std::string const& s) // explicit template arguments
{
// to something specific for std::string
}

// alternatively:
template<>
void demo(std::std::string const& s) // deduced template arguments
{ }

You usually do so, though, only if unavoidable, e.g. some templated function calls yet another templated function with explicit template arguments and you need to adjust this other function for a specific type.

Otherwise you would rather prefer overloading; in your case that could look like:

template <typename T>
T const& max(T const arr[], size_t size) { /* ... */ }
// ^
// note that in the general variant I'd rather return a reference to avoid
// unnecessary copies e.g. for `std::string`

// note the missing template definition!
// -> no template -> an OVERLOAD to the templates existing!
char const* max(char const* const arr[], size_t size) { /* ... */ }
// ^ can omit the reference, we have pointers anyway

Yet a totally different alternative might be providing yet another template argument that specifies the comparison, just as std::max_element does, e.g. like

template <typename T, typename Cmp = std::less<T>>
T* max(T&, T&, Cmp const& = Cmp()) { /* ... */ }

Instead of writing a separate function for finding the maximum you could now just provide a custom comparator:

char const* s[] = { "hello", "world" };
auto m = max
(
s, sizeof(s)/sizeof(*s),
[](auto x, auto y) { return strcmp(x, y) < 0; }
);

Now if you finally insist on the specialisation it would look like this:

template <typename T
T const& max(T const arr[], size_t size) { /* ... */ }

// here with deduced template arguments:
template<>
char const*& max(char const* const arr[], size_t size) { /* ... */ }
// ^
// now we need the reference (if you actually add as I proposed)
// to remain compatible with the base template


Related Topics



Leave a reply



Submit