Ellipse return function: can we set the size of the parameter packet?

Consider the following code:

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

As shown in the example, the third call fworks just fine, even if the number of arguments is incorrect, since it is not an error at all for the backup function.

Is there a way to force the number of arguments to use this ellipsis?
I mean, can I check at compile time that the size of the argument list is exactly equal 1, regardless of whether the main function or the backup is selected?

Good solutions are also those that include only the first function of the template and lead to errors with errors instead of soft errors due to the size of the parameter packet.


, . : int/char ; ; ...
, .
, - .

+4
2

, :

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

+1

(assert), , paramemters:

#include <utility>
#include <iostream>
template <typename...Args>
struct size_assert{
    template <typename T,typename R,typename... Params>
    constexpr static bool assert(R(T::*)(Params...) )
    {
        static_assert(sizeof...(Args) == sizeof...(Params),"Incorrect size of arguments!");
        return true;
    }
};

struct S {

    template<typename T, typename... A, bool =  size_assert<A...>::assert(&T::f)>
    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() {
   // std::cout <<fc(&f);
    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)
}
0

Source: https://habr.com/ru/post/1652860/


All Articles