c – 使用省略号的后退功能:我们可以强制参数包的大小吗?

请考虑以下代码:

#include <utility>
#include <iostream>

struct S {
    template<typename T, typename... A>
    auto f(A&&... args) -> decltype(std::declval<T>().f(std::forward<A>(args)...), void()) {
        std::cout << "has f(int)" << std::endl;
    }

    template<typename>
    void f(...) {
        std::cout << "has not f(int)" << std::endl;
    }
};

struct T { void f(int) { } };
struct U { };

int main() {
    S s;
    s.f<T>(42); // -> has f(int)
    s.f<U>(42); // -> has not f(int)
    // oops
    s.f<T>(); // -> has not f(int)
}

如示例所示,对f的第三次调用工作得很好,即使参数的数量是错误的,因为它对于回退函数完全没有错.

当省略号以这种方式涉及时,有没有办法强制参数的数量?
我的意思是,我可以在编译时检查参数列表的大小是否正好为1,无论是选择主函数还是后备函数?

良好的解决方案也只涉及第一个模板功能,并且由于参数包的大小而导致硬错误而不是软错误.

当然,它可以通过几种技术解决,而无需使用可变参数.举个例子:int / char调度内部模板方法;显式指定参数列表;随你…
问题不是关于做到这一点的替代方法,我已经知道了.
这只是要知道我是否遗漏了一些基本的东西,或者这是不可能的,这就是全部.

最佳答案 如果我正确理解您的问题,您可以添加一个图层:

struct S {
private:
    template<typename T, typename... A>
    auto f_impl(A&&... args)
    -> decltype(std::declval<T>().f(std::forward<A>(args)...), void()) {
        std::cout << "has f(int)" << std::endl;
    }

    template<typename>
    void f_impl(...) {
        std::cout << "has not f(int)" << std::endl;
    }
public:

    template<typename T, typename A>
    auto f(A&& args) { return f_impl<T>(std::forward<A>(arg)); }
};

有了特质,你可以这样做

template <typename T, typename ... Ts>
using f_t = decltype(std::declval<T>().f(std::declval<Ts>()...));

template <typename T, typename ... Ts>
using has_f = is_detected<f_t, T, Ts...>;

struct S {
    template<typename T, typename... A>
    std::enable_if_t<has_f<T, A&&...>::value && sizeof...(A) == 1> f(A&&... args)
    {
        std::cout << "has f(int)" << std::endl;
    }

    template<typename T, typename... A>
    std::enable_if_t<!has_f<T, A&&...>::value && sizeof...(A) == 1>  f(A&&... args) {
        std::cout << "has not f(int)" << std::endl;
    }
};

Demo

点赞