C++11 函数模板特化为 class 方法(如果存在)

C++11 function template specializes as a class method if it exists

我有这个函数模板:

template <class T>
Json::Value write_json(const T& object);

T是一个int时,特化很简单:

template <>
Json::Value write_json(const int& object) {
  Json::Value output;
  output = object;
  return output;
};

然而,对于更复杂的 classes,我希望它调用一个存在的方法:

template <typename T>
struct has_write_json_method {
    template <typename U>
    static constexpr decltype(std::declval<U>().write_json(), bool()) test(int) { return true; };

    template <typename U>
    static constexpr bool test(...) { return false; }

    static constexpr bool value = test<T>(int());
};

template <class T>
typename std::enable_if<has_write_json_method<T>::value, Json::Value>::type write_json(const T& object)  {
    object.write_json();
};

例如,对于 class foo:

Json::Value foo::write_json(void) { 
  Json::Value output;
  output = 42;
  return output;
};

我想给每个 class 打电话:

int x_int;
write_json(x_int);
foo x_foo;
write_json(x_foo);

然而,我得到了:

error: call of overloaded 'write_json(const foo&)' is ambiguous

我怎样才能消除这种歧义?

您也应该在另一个重载上应用 SFINAE,以避免当类型 T 具有方法 write_json.

时出现歧义
template <class T>
typename std::enable_if<!has_write_json_method<T>::value, void>::type write_json(const T& object);
//                      ^

LIVE

您可以进行代码调度:

#include <type_traits>

template <class T>
void write_json_impl(const T& object, std::true_type)  {
    object.write_json();
};

template <class T>
void write_json_impl(const T& object, std::false_type)  {
};

template <typename T>
struct has_write_json_method {
    template <typename U>
    static constexpr decltype(std::declval<U>().write_json(), bool()) test(int) { return true; };

    template <typename U>
    static constexpr bool test(...) { return false; }

    static constexpr bool value = test<T>(int());

    // Add this:
    using type = typename std::conditional<value, std::true_type, std::false_type>::type;
    // or this:
    // using type = std::integral_constant<bool, value>;
};

template <class T>
void write_json(const T& object)
{
    return write_json_impl(object, typename has_write_json_method<T>::type{});
};

struct Foo { void write_json() const {} };

int main()
{
    Foo f;
    write_json(f);
    write_json(0);
}

Live.

我会用更简单的方式来写:

template<class T>
struct json_helper {   
    static void write_json(const T& t) {
        return t.write_json();
    }
};

template<class T>
void write_json(const T& t) {
    return json_helper<T>::write_json(t);
}


template<>
struct json_helper<int>{
    static void write_json(const int &i) {
    }
};

struct foo {
    void write_json(void) const { }
};
struct bar {};

int main() {
    foo f;
    write_json(f);
    // write_json(bar{}); << this won't work
}

Live example