Reputation: 4298
Suppose the following class:
class JsonDocument
{
public:
using RootType = size_t;
constexpr static RootType ObjectRoot = 1;
constexpr static RootType ArrayRoot = 2;
template<
RootType T = ObjectRoot,
std::enable_if<T == ObjectRoot || T == ArrayRoot>
>
JsonDocument();
JsonDocument(const std::string &json_str);
};
I want to specialize JsonDocument
constructor for both ObjectRoot
and ArrayRoot
. The problem is, as there are no arguments, T
couldn't be inferred. Explicitly specializing it doesn't work, neither this way:
class JsonDocument
{
// ...
// Doesn't work
template<> JsonDocument<ObjectRoot>();
template<> JsonDocument<ArrayRoot>();
}
Nor this:
template<> JsonDocument::JsonDocument<ObjectRoot>()
{
}
template<> JsonDocument::JsonDocument<ArrayRoot>()
{
}
So is it impossible at all? Is there any way to do it?
P.S.: This question is different; as deduction can be made.
Upvotes: 0
Views: 41
Reputation: 13110
Make the whole class a template. I think this makes sense because you are going to select which root to use at compile time anyway. (C++17 example)
#include <type_traits>
struct ObjectRoot
{};
struct ArrayRoot
{};
// helper constexpr for readability (in C++20 consider a concept)
template<typename root_t>
constexpr bool is_valid_json_root = std::is_same_v<root_t, ObjectRoot> || std::is_same_v<root_t, ArrayRoot>;
template<typename root_t,typename enable_t = void>
class JsonDocument;
template<typename root_t>
class JsonDocument<root_t,std::enable_if_t<is_valid_json_root<root_t>>>
{
public:
// no need for compile time constants.
// you make the selection for your root_t at compile time anyway
//using RootType = size_t;
//constexpr static RootType ObjectRoot = 1;
//constexpr static RootType ArrayRoot = 2;
JsonDocument() {}
};
int main()
{
JsonDocument<ObjectRoot> doc_from_root;
JsonDocument<ArrayRoot> doc_from_array;
}
Upvotes: 0