【问题标题】:Checking correctness of function call expression检查函数调用表达式的正确性
【发布时间】:2014-06-15 19:52:03
【问题描述】:

std::result_of 在编译时计算调用表达式的返回类型。

正如the reference 所说,如果调用格式错误,std::result_of 的实例化会导致编译错误。但是假设我们需要在获取结果类型之前检查调用是否格式正确。

有没有办法编写一个特征来检查调用表达式是否格式正确?

类似:

template<typename F , typename... ARGS>
struct is_valid_call : public impl::is_valid_call<F,typelist<ARGS...>>
{};

namespace impl
{
    struct sfinae_result{};

    template<typename F , typename ARGS , typename ENABLED = sfinae_result>
    struct is_valid_call;

    template<typename F , typename... ARGS>
    struct is_valid_call<F,typelist<ARGS...>,
                         decltype( std::declval<F>()(std::declval<ARGS>()...) )
                        > : 
        public std::true_type
    {};

    template<typename F , typename... ARGS>
    struct is_valid_call<F,typelist<ARGS...>,sfinae_result> : 
        public std::false_type
    {};
}

编辑:当然是doesn't work

发布的解决方案

【问题讨论】:

  • @jrok 当然,对于真正的实现,我应该处理函数指针、仿函数和 lambda。但是假设这只是函子,以简化问题(解决方案是相同的,不是吗?只有更多的情况)。我的意图是在 SFINAE 上下文中使用这种特征,特别是(例如)检查给定的转换函数是否适用于特定类型。

标签: c++ c++11 sfinae typetraits


【解决方案1】:

以下是可行的方法:

#include <type_traits>
#include <utility>

template<typename F, typename... Args>
struct is_valid_call {
private:
    template<typename FF, typename... AA>
    static constexpr auto check(int) ->
    decltype( std::declval<FF>()(std::declval<AA>()...), std::true_type());

    template<typename FF, typename... AA>
    static constexpr std::false_type check(...);
public:
    static constexpr bool value = decltype(check<F, Args...>(0)){};
};

#include <cstdio>

int main()
{
   printf("%d", int (is_valid_call<decltype(&puts), const char*>::value));
   printf("%d", int (is_valid_call<decltype(&puts), double>::value));
}

输出:10

【讨论】:

  • 有什么特别的理由使用逗号评估技巧而不是在模板上写declval
  • 原因是我没有想太多:) 是的,那可能会更干净。
  • @Manu343726 等等,在二读时,我不确定我是否理解你:)
  • 这可能就是你被咬的原因——你的实现不起作用,因为impl::is_valid_call 的第二个专业化更加专业化并且总是被选中。它认为,至少 - 现在是星期天傍晚,我的头脑不再那么清晰了......我也不明白你为什么会失望 - 这是你的好旧表达 SFINAE。
  • +1 不错的解决方案。我称之为invokable 的一个密切相关(且有用)的特征。它允许来自 20.9.2/p1 的所有 5 个子弹(is_valid_call 只允许第 5 个子弹)。这个扩展的特征涵盖(例如)您可以构造std::threadstd::function 的参数,包括指向成员函数的指针和指向成员数据的指针。恕我直言,具有足够的挑战性和实用性以保证标准化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多