没有命名参数的可变参数函数
Variadic function without named argument
我注意到,GCC 和 MSVC 都对以下代码感到满意:
#include <iostream>
void foo(...);
int main()
{
foo();
}
void foo(...)
{
std::cout << "foo\n";
}
更具体地说,代码是 运行 GCC 6.2.0 和 Visual Studio 2015。
我知道 C 在省略号之前至少需要一个 named 参数,它允许使用专门的 va_start
、va_args
处理任意数量的参数和来自 <stdarg.h>
的 va_end
宏(这里是 <cstdarg>
)header。否则,它甚至不会编译。
C++ 是否对 "pure ellipsis" 形式有一些特殊处理,或者它是否不适合获取参数,即允许,但完全不切实际?
C++ Variadiac arguments are explained here。 C++ 支持此语法,但参数不可访问:
In the C programming language, at least one named parameter must appear before the ellipsis parameter, so printz(...);
is not valid.
In C++, this form is allowed even though the arguments passed to such
function are not accessible, and is commonly used as the fallback
overload in SFINAE, exploiting the lowest priority of the ellipsis
conversion in overload resolution. This syntax for variadic arguments
was introduced in 1987 C++ without the comma before the ellipsis. When
C89 adopted function prototypes from C++, it replaced the syntax with
one requiring the comma. For compatibility, C++98 accepts both
C++-style f(int n...)
and C-style f(int n, ...)
在C++中是允许的,因为即使之前没有命名参数,...
也只是一个不可访问的可变参数。
在 C 中,没有重载,并且具有仅接收 ...
的函数可能是运行时错误的重要来源。无法访问的可变参数在 C 中没有用。
在 C++ 中,它目前用作 sfinae 的接收器函数。在解析对具有可变参数的函数的调用之前,如果可能,编译器将始终选择其他重载。对于 sfinae 目的很实用:
template<typename F, typename... Ts>
struct is_callable {
private:
template<typename T, typename... Args>
static decltype(
static_cast<void>(std::declval<T>()(std::declval<Args>()...)),
std::true_type{}
) test(int);
template<typename...>
static std::false_type test(...); // not a template variadic, classic vararg here.
public:
// Here, the compiler will try the first version of the function
// Because '...' is not the preferred overload
// If the return type expression don't yield to a type, the compiler
// will have no choice but to pick the variadic one,
// resulting in a std::false_type
using type = decltype(test<F, Ts...>(0));
};
我注意到,GCC 和 MSVC 都对以下代码感到满意:
#include <iostream>
void foo(...);
int main()
{
foo();
}
void foo(...)
{
std::cout << "foo\n";
}
更具体地说,代码是 运行 GCC 6.2.0 和 Visual Studio 2015。
我知道 C 在省略号之前至少需要一个 named 参数,它允许使用专门的 va_start
、va_args
处理任意数量的参数和来自 <stdarg.h>
的 va_end
宏(这里是 <cstdarg>
)header。否则,它甚至不会编译。
C++ 是否对 "pure ellipsis" 形式有一些特殊处理,或者它是否不适合获取参数,即允许,但完全不切实际?
C++ Variadiac arguments are explained here。 C++ 支持此语法,但参数不可访问:
In the C programming language, at least one named parameter must appear before the ellipsis parameter, so
printz(...);
is not valid.In C++, this form is allowed even though the arguments passed to such function are not accessible, and is commonly used as the fallback overload in SFINAE, exploiting the lowest priority of the ellipsis conversion in overload resolution. This syntax for variadic arguments was introduced in 1987 C++ without the comma before the ellipsis. When C89 adopted function prototypes from C++, it replaced the syntax with one requiring the comma. For compatibility, C++98 accepts both C++-style
f(int n...)
and C-stylef(int n, ...)
在C++中是允许的,因为即使之前没有命名参数,...
也只是一个不可访问的可变参数。
在 C 中,没有重载,并且具有仅接收 ...
的函数可能是运行时错误的重要来源。无法访问的可变参数在 C 中没有用。
在 C++ 中,它目前用作 sfinae 的接收器函数。在解析对具有可变参数的函数的调用之前,如果可能,编译器将始终选择其他重载。对于 sfinae 目的很实用:
template<typename F, typename... Ts>
struct is_callable {
private:
template<typename T, typename... Args>
static decltype(
static_cast<void>(std::declval<T>()(std::declval<Args>()...)),
std::true_type{}
) test(int);
template<typename...>
static std::false_type test(...); // not a template variadic, classic vararg here.
public:
// Here, the compiler will try the first version of the function
// Because '...' is not the preferred overload
// If the return type expression don't yield to a type, the compiler
// will have no choice but to pick the variadic one,
// resulting in a std::false_type
using type = decltype(test<F, Ts...>(0));
};