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);
// ^
您可以进行代码调度:
#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);
}
我会用更简单的方式来写:
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
}
我有这个函数模板:
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);
// ^
您可以进行代码调度:
#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);
}
我会用更简单的方式来写:
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
}