Search code examples
c++11templatesdecltype

Code explanation of the json11 library about implicit constructor


I'm reading the source code of the main json11 header file.

It contains the following declaration:

template <class T, class = decltype(&T::to_json)>
Json(const T & t) : Json(t.to_json()) {}

I'm trying to find some documentation about this usage of decltype and class inside a template declaration but no success.

Does this construction/usage has a name in C++? Any good reference about it?


Solution

  • It's using SFINAE ("Substitution Failure Is Not An Error"), a common technique for advanced template stuff. In this case, it's used as a crude(1) test whether the type T has a function named to_json.

    How it works: if the expression T::to_json is well-formed (there is something named to_json inside the type T), decltype(T::to_json) denotes a valid type and the constructor template can be used normally.

    However, if T::to_json is ill-formed (i.e. if there is no to_json member inside T), it means substituting the template argument for T has failed. Per SFINAE, this is not an error of the entire program; it just means that the template is removed from further consideration (as if it was never part of the class).

    The effect is thus that if type T has a member to_json, you can use an object of type T to initialise a Json object. If there is no such member in T, the constructor will not exist.


    (1) I'm saying crude test because this only checks that T has such a member. It doesn't check that the member is a function which can be invoked without arguments and returns something another constructor of Json can accept. A tighter-fitting test might look something like this:

    template <class T, class = std::enable_if_t<std::is_constructible<Json, decltype(std::declval<const T>().to_json())>::value>>
    Json(const T & t) : Json(t.to_json()) {}
    

    [Live example]