我有以下代码:
struct has_to_string {};
struct has_error_string {};
template<typename T>
struct checker
{
template<typename, typename> struct checker_helper;
template<typename C>
static has_to_string test(checker_helper<C, decltype(&C::toString)> *);
template<typename C> // Enable this test only if the previous one has failed
static has_error_string test(checker_helper<C, decltype(&C::errorString)> *);
template<typename C>
static std::false_type test(...);
using type = decltype(test<T>(nullptr));
};
template<typename T>
using checker_t = typename checker<T>::type;
template<typename T1, typename T2, typename R>
using enable_if_same = typename std::enable_if<std::is_same<T1, T2>::value, R>::type;
template<typename T, typename C>
inline enable_if_same<std::false_type, C, QString> _moduloHelper(const QString & s, const T & value)
{ return s.arg(value); }
template<typename T, typename C>
inline enable_if_same<has_to_string, C, QString> _moduloHelper(const QString & s, const T & value)
{ return s.arg(value.toString()); }
template<typename T, typename C>
inline enable_if_same<has_error_string, C, QString> _moduloHelper(const QString & s, const T & value)
{ return s.arg(value.errorString()); }
如果模板参数具有此功能,则此代码允许我调用特定函数(在本例中为toString
或errorString
)。这完美无缺。我唯一的问题是当我将这个函数用于同时具有errorString
和toString
函数的类时。
在这种情况下,由于checker::test
函数的模糊调用,程序不再编译。我完全理解为什么代码不能编译但是如果这种情况附加我想每次都选择toString
版本但我不知道该怎么做。
BTW这是如何调用_moduloHelper
:
int main()
{
QString str("%1");
_moduloHelper<QUrl, checker_t<QUrl>>(str, QUrl());
}
当然我有一个包装器,但这不是重点。
答案 0 :(得分:1)
我会提供我的解决方案,它不像你最初那样简约。有时在C ++模板中元编程代码增长得非常快。但是,除了解决问题之外,我的解决方案还有另一个优点 - 它会检查函数的返回类型。您可以考虑使用预处理器来减少代码冗余。
template <typename T>
struct to_string_checker {
template <typename C,
typename
= typename std::enable_if<std::is_same<decltype(std::declval<C>().toString()),
QString>::value,
void>::type>
static std::true_type test(int*);
template <typename C>
static std::false_type test(...);
constexpr static bool value = decltype(test<T>(nullptr))::value;
};
template <typename T>
struct to_error_string_checker {
template <
typename C,
typename = typename std::
enable_if<std::is_same<decltype(std::declval<C>().errorString()), QString>::value,
void>::type>
static std::true_type test(int*);
template <typename C>
static std::false_type test(...);
constexpr static bool value = decltype(test<T>(nullptr))::value;
};
template <typename T>
typename std::enable_if<to_string_checker<T>::value, QString>::type
_moduloHelper(const QString& s, const T& value) {
return s.arg(value.toString());
}
template <typename T>
typename std::enable_if<(!to_string_checker<T>::value
&& to_error_string_checker<T>::value),
QString>::type
_moduloHelper(const QString& s, const T& value) {
return s.arg(value.errorString());
}
template <typename T>
typename std::enable_if<(!to_string_checker<T>::value
&& !to_error_string_checker<T>::value),
QString>::type
_moduloHelper(const QString& s, const T& value) {
return s.arg(value);
}
int main() {
QString str("%1");
_moduloHelper(str, QUrl());
QString str2("%1");
_moduloHelper(str, 10).toStdString();
}