Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I specialize forward declared template?

Can I specialize forward declared template? For example:

template <typename T> class A;

template <>
class A<char> {
    char a[1000];
};

int main()
{
    [[maybe_unused]] A<char> a;
    return 0;
}

What do I want to achieve?

As we know, we have to specialize std::hash to use it with some hash-table-based types. Standard std::hash specialization requires to include <functional> in the header file and then specialize it. I use this header file in many places, and the compilation time of <functional> is pretty big. So I want to move my specialization to source (cpp) file.

my_type.hpp:

class my_type {/*...*/};

namespace std {

template <typename T>
struct hash;

template <>
struct hash<my_type>
{
    size_t operator()(my_type m) const;
};
} // namespace std

my_type.cpp:

#include "my_type.hpp"
#include <functional>
namespace std {
size_t std::hash<my_type>::operator()(my_type v) const
{
    return std::hash<decltype(v.value())>{}(v.value());
}
} // namespace std

This solution works, but is it legal in terms of ISO standard?

EDIT/NOTE: It doesn't work with libc++ (clang std implementation), because it defines std::hash as std::__1::hash, where __1 is inline namespace. This partially answers the question.

like image 771
Mariusz Jaskółka Avatar asked Sep 01 '20 08:09

Mariusz Jaskółka


1 Answers

The general question about A is that yes, it's allowed. An explicit specialization is disjoint from the primary template. It can be defined as complete or incomplete, regardless of how the primary is defined.

As for your more specific question about std::hash, not it's not alright. You violate

[namespace.std]

1 Unless otherwise specified, the behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std.

2 Unless explicitly prohibited, a program may add a template specialization for any standard library class template to namespace std provided that (a) the added declaration depends on at least one program-defined type and (b) the specialization meets the standard library requirements for the original template.

Forward declaring std::hash is not a declaration of a specialization that depends on a user defined type. It's a plain declaration that falls under the specification of paragraph 1. There is no wording that allows to forward declare std::hash anywhere else in the standard. So this is undefined behavior.

like image 184
StoryTeller - Unslander Monica Avatar answered Nov 15 '22 04:11

StoryTeller - Unslander Monica