简体   繁体   English

C ++ SFINAE运算符/函数结果类型检查

[英]C++ SFINAE operator/function result type check

I am writing a template-based class for Polynomials. 我正在为多项式编写基于模板的类。 (Evaluation, some operations between Polynomials, differentiation, ...), like this: template <typename _ty> class Polynomial{... (求值,多项式之间的一些运算,微分,...),如下所示: template <typename _ty> class Polynomial{...

For the to_string function (and the std::ostream -left-shift-override), I had to check, if _ty supports the < -operator (ie yes for real numbers, no for complex numbers), so that the string could be formatted nicely. 对于to_string函数(和std::ostream -left-shift-override),我不得不检查_ty支持< -operator(即,对于实数为yes,对于复数为no),以便该字符串可以为格式很好。 For this I use this code: 为此,我使用以下代码:

#include <type_traits>

template <class _op, class... _ty, typename = decltype(std::declval<_op>()(std::declval<_ty>()...))>
std::true_type impl_test(const _op&, const _ty&...) { return std::true_type(); }
std::false_type impl_test(...) { return std::false_type(); }
template <class> struct supports;
template <class _op, class... _ty> struct supports<_op(_ty...)> : decltype(impl_test(std::declval<_op>(), std::declval<_ty>()...)){};

#define is_ineq_supported(type) supports<std::less<>(type, type)>()

In short, is_ineq_supported(type) returns an std::true_type if there is a valid overload for the < -operator, and a false_type if not. 简而言之,如果< std::true_type有有效的重载,则is_ineq_supported(type)返回std::true_type否则返回false_type The corresponding functions can then be called with a true_type or false_type as the distinguishing argument, like this: 然后可以使用true_typefalse_type作为区别参数来调用相应的函数,如下所示:

template <typename _ty> void do_stuff(_ty arg, const std::true_type&) {
    // do stuff with the '<'-operator
}

template <typename _ty> void do_stuff(_ty arg, const std::false_type&) {
    // do stuff without the '<'-operator
}

template <typename _ty> void do_stuff(_ty arg) {
    do_stuff(arg, is_ineq_supported(_ty));
}

I also have a Vector class, that overloads the binary * -operator with the dot product, so it returns a double . 我也有一个Vector类,它用点积重载了二进制* -operator,因此它返回double But for a polynomial, it only makes sense, to have coefficients and arguments, which return the same type when multiplied with one another. 但是对于一个多项式来说,只有系数和自变量相乘时才返回相同的类型,这才有意义。

My problem is the following: I'd like to have a way of checking, if the given operation returns a specified type. 我的问题如下:如果给定的操作返回指定的类型,我想有一种检查方法。 (maybe a similar macro?) I think, the simplest would be something that returns a true_type if the result type matches the argument type and a false_type otherwise. (也许是类似的宏?)我认为,如果结果类型与参数类型匹配,则最简单的方法将返回true_type否则返回false_type Of course, more general solutions are even better. 当然,更一般的解决方案甚至更好。

In case, the IDE and Compiler matter: I'm using Visual Studio 2015 with default settings. 万一IDE和编译器很重要:我在使用Visual Studio 2015(默认设置)。

Here is a generic, cross-platform solution using fit::is_callable , which will be eventually added to Boost. 这是一个使用fit::is_callable的通用跨平台解决方案,它将最终添加到Boost中。 Also keep your eye out for std::is_callable in C++17. 另外,请注意C ++ 17中的std::is_callable

No macros necessary: 不需要宏:

#include <type_traits>
#include <iostream>
#include <fit/is_callable.hpp>

// std::less doesn't SFINAE, so we make our own test
struct less_test {
    template<typename L, typename R>
    auto operator()(L l, R r) -> decltype(l < r);
};

template<typename T>
using is_less_than_comparable = fit::is_callable<less_test, T, T>;

// operator< version (replace with your implementation)
template <typename T> constexpr auto
do_stuff(T arg, const std::true_type&) {
    return std::integral_constant<int, 0>{};
}

// other version (replace with your implementation)
template <typename T> constexpr auto
do_stuff(T arg, const std::false_type&) {
    return std::integral_constant<int, 1>{};
}

template <typename T> constexpr auto
do_stuff(T arg) {
    return do_stuff(arg, is_less_than_comparable<T>{});
}

struct foo {};

int main() {

    //is not less-than comparable
    static_assert(do_stuff(foo{}) == 1, "");

    //is less-than comparable
    static_assert(do_stuff(0) == 0, "");
}

You should probably reconsider your member method detectors and use the most C++11-ish void_t based solution. 您可能应该重新考虑成员方法检测器,并使用大多数基于C ++ 11的 void_t解决方案。

That said, if I had to update your solution, probably the following code is a viable approach: 就是说,如果我必须更新您的解决方案,则以下代码可能是一种可行的方法:

template <class _op, class _ret, class... _ty>
typename std::enable_if<std::is_same<decltype(std::declval<_op>()(std::declval<_ty>()...)), _ret>::value, std::true_type>::type
impl_test(const _op&, const _ty&...) {
    return std::true_type();
}

This will work as it follows: 这将如下工作:

struct S { int operator()() { return 42; } };

int main() {
    assert((impl_test<S, int>(S{})));
    // this will give you an error at compile time
    // assert((impl_test<S, double>(S{})));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM