enable_if template param is lambda (with particular signature)

爷,独闯天下 提交于 2021-01-20 08:24:22

问题


I have something this:

template<typename T>
class Image {
    Image(int w, int h, T defaultVal){
        for(int i=0; i<h; i++)
            for(int j=0; j<w; j++)
                pixel(j, i) = defaultVal;
    }
    template<typename F>
    Image(int w, int h, F initializer){
        for(int i=0; i<h; i++)
            for(int j=0; j<w; j++)
                pixel(j, i) = initializer(j, i);
    }
    // ...
};

My intention is to be able to instantiate an Image like this:

Image<int> img0(w, h, 0); // image of zeroes
Image<int> imgF(w, h, [](int j, int i){ // checkerboard image
    return (j/10+i/10) % 2;
});

But of course the second constructor signature will conflict with the first constructor signature. To resolve this conflict I want to restrict the second constructor's possible template instantiations.

I don't want to make it too complicated. Can you help me? My attempt:

template<typename F, typename = std::enable_if_t< // what now? how to check that F is callable (and if simple to check, with appropriate signature)

回答1:


You're looking for std::is_invocable:

template<typename F, typename = std::enable_if_t<
    std::is_invocable<F&, int, int>>

F& because you're invoking it as an lvalue, and then after that it's just a list of types of parameters.


The above requires C++17. It is implementable on C++14, but in your case we can also take a much simpler approach and just do:

template <typename F, typename = decltype(std::declval<F&>()(1, 1))>

F& for the same reason as above, and the rest of the expression is more familiar. Since we're calling with ints we don't care about the other things that INVOKE allows for (e.g. pointers to members).



来源:https://stackoverflow.com/questions/50859115/enable-if-template-param-is-lambda-with-particular-signature

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!