如果前一个成功,则禁用测试条件
Disable test condition if the previous one succeeded
我有以下代码:
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
函数的 class 一起使用时。
在这种情况下,由于 checker::test
函数的调用不明确,程序不再编译。我完全理解为什么代码无法编译,但如果在这种情况下追加,我想每次都选择 toString
版本,但我不知道该怎么做。
顺便说一句,这是如何调用 _moduloHelper
:
int main()
{
QString str("%1");
_moduloHelper<QUrl, checker_t<QUrl>>(str, QUrl());
}
当然我对此有一个包装,但这不是重点。
我会提供我的解决方案,它并不像您最初可能的那样简约。有时在 C++ 模板元编程代码中增长得非常快。但是,除了解决您的问题之外,我的解决方案还有另一个优点 - 它检查函数的 return 类型。您可以考虑使用预处理器来减少代码冗余。
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();
}
我有以下代码:
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
函数的 class 一起使用时。
在这种情况下,由于 checker::test
函数的调用不明确,程序不再编译。我完全理解为什么代码无法编译,但如果在这种情况下追加,我想每次都选择 toString
版本,但我不知道该怎么做。
顺便说一句,这是如何调用 _moduloHelper
:
int main()
{
QString str("%1");
_moduloHelper<QUrl, checker_t<QUrl>>(str, QUrl());
}
当然我对此有一个包装,但这不是重点。
我会提供我的解决方案,它并不像您最初可能的那样简约。有时在 C++ 模板元编程代码中增长得非常快。但是,除了解决您的问题之外,我的解决方案还有另一个优点 - 它检查函数的 return 类型。您可以考虑使用预处理器来减少代码冗余。
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();
}