【问题标题】:C++ SFINAE operator/function result type checkC++ SFINAE 运算符/函数结果类型检查
【发布时间】:2016-09-21 14:53:11
【问题描述】:

我正在为多项式编写一个基于模板的类。 (求值,多项式之间的一些运算,微分,...),像这样: template <typename _ty> class Polynomial{...

对于to_string 函数(和std::ostream-left-shift-override),我必须检查_ty 是否支持<-运算符(即对于实数是,对于复数是否),以便可以很好地格式化字符串。为此,我使用以下代码:

#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)>()

简而言之,如果&lt; 运算符存在有效的重载,is_ineq_supported(type) 返回 std::true_type,否则返回 false_type。然后可以使用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));
}

我还有一个 Vector 类,它使用点积重载二进制 *-运算符,因此它返回 double。但是对于多项式来说,只有系数和参数在相乘时返回相同的类型才有意义。

我的问题如下:如果给定的操作返回指定的类型,我想有一种检查方法。 (也许是一个类似的宏?)我认为,最简单的方法是如果结果类型与参数类型匹配则返回 true_type,否则返回 false_type。当然,更通用的解决方案会更好。

如果 IDE 和编译器很重要:我使用的是默认设置的 Visual Studio 2015。

【问题讨论】:

  • "(...) if the given operation return a specified type",也许最好检查返回的类型是否可以隐式转换为某种东西?跨度>
  • std::is_same(或std::is_convertible)?

标签: c++ c++11 sfinae


【解决方案1】:

这是一个使用 fit::is_callable 的通用跨平台解决方案,最终将添加到 Boost 中。还要留意 C++17 中的 std::is_callable

不需要宏:

#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, "");
}

【讨论】:

    【解决方案2】:

    您可能应该重新考虑您的成员方法检测器并使用最C++11-ish基于void_t 的解决方案。

    也就是说,如果我必须更新您的解决方案,可能以下代码是一种可行的方法:

    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();
    }
    

    这将按如下方式工作:

    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{})));
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-25
      • 2011-02-06
      • 2015-09-03
      • 2015-06-03
      • 1970-01-01
      相关资源
      最近更新 更多