充分利用static_assert和std :: is_invocable

时间:2017-07-07 20:01:34

标签: c++ c++17 sfinae static-assert

我有一个包含多个函数对象的库,可能只接受几种类型,具体取决于std::is_integral。我希望std::is_invocable在条件失败时返回false,但当用户尝试调用函数对象的实例时,我还想要一条很好的static_assert错误消息。这是我目前拥有的函数对象的简化示例:

struct function
{
    template<typename Iterator>
    auto operator()(Iterator first, Iterator last) const
        -> std::enable_if_t<std::is_integral_v<
            typename std::iterator_traits<Iterator>::value_type
        >>
    { /* something */ }
};

通过这样的实现,std::is_invocable在预期不满足SFINAE条件时是std::false_type,但是当用户尝试使用不具有参数的参数调用函数对象时,会遇到丑陋的SFINAE错误消息符合SFINAE条件。

为了获得更好的错误消息,我尝试了以下解决方案:

struct function
{
    template<typename Iterator>
    auto operator()(Iterator first, Iterator last) const
        -> void
    {
        static_assert(std::is_integral_v<typename std::iterator_traits<Iterator>::value_type>,
                      "function can only be called with a collection of integers");

        /* something */
    }
};

通过此实现,当不满足原始SFINAE条件时,用户会收到友好的错误消息,但当询问std::is_invocable实例是否可以处理不属于std::true_type的实例时,functionstd::is_integral满足decltype(auto)

我尝试了一些涉及if constexprstd::is_invocable和其他机制的技巧和变体,但无法获得错误消息很好的类以及std::false_type与预期function对应的位置1}}询问是否可以使用不正确的类型调用std::is_invocable

我在这里缺少什么?有没有办法同时获得正确的const mongoose = require('mongoose') 用户友好的错误消息?

1 个答案:

答案 0 :(得分:7)

这是一个糟糕的方式。添加重载:

template <typename Iterator>
auto operator()(Iterator first, Iterator last) const
    -> std::enable_if_t<std::is_integral_v<
        typename std::iterator_traits<Iterator>::value_type
    >>;

template <typename Iterator, class... Args>
void operator()(Iterator, Iterator, Args&&... ) const = delete; // must be integral

这满足is_invocable<>条件,因为约束函数模板更专业和更受欢迎 - 所以如果条件满足,则函数是可调用的,否则它被删除。

这在错误情况下做得更好一些,因为如果你试图调用它,你会得到:

foo.cxx: In function ‘int main()’:
foo.cxx:31:13: error: use of deleted function ‘void function::operator()(Iterator, Iterator, Args&& ...) const [with Iterator = std::__cxx11::basic_string<char>*; Args = {}]’
     f(&i, &i);
             ^
foo.cxx:19:10: note: declared here
     void operator()(Iterator, Iterator, Args&&... ) const = delete; // must be integral
          ^~~~~~~~

评论显示在错误消息中,有点像静态断言消息?

这实际上是Concepts的动机之一。使用requires代替enable_if,我们得到:

foo.cxx: In function ‘int main()’:
foo.cxx:26:13: error: no match for call to ‘(function) (std::__cxx11::string*, std::__cxx11::string*)’
     f(&i, &i);
             ^
foo.cxx:11:10: note: candidate: void function::operator()(Iterator, Iterator) const requires  is_integral_v<typename std::iterator_traits<_Iter>::value_type> [with Iterator = std::__cxx11::basic_string<char>*]
     void operator()(Iterator first, Iterator last) const
          ^~~~~~~~
foo.cxx:11:10: note:   constraints not satisfied
foo.cxx:11:10: note: ‘is_integral_v<typename std::iterator_traits<_Iter>::value_type>’ evaluated to false

我想......好一点。