某些C++实现(例如,电池供电的嵌入式设备)可能没有用或无法跟踪当前的日期和时间.
的C标准具体地允许这样的实施方式.引用ISO/IEC 9899:1999 7.23.2.4(强调我的):
time函数返回实现对当前日历时间的最佳近似值.如果日历时间不可用,则返回值(time_t)( - 1).
C++ 11引入了chrono
库和std::chrono::system_clock::now()
函数,用于从系统范围的实时时钟获取挂钟时间.该函数被声明为noexcept
,因此它不能抛出任何异常来指示不可用,也不允许返回任何特殊值(如-1
C的情况).
但是对于C++ 11,C++ 14和C++ 17,仍然存在漏洞.标准没有指定时钟的纪元,因此符合要求的实施可以将纪元设置为启动时(或程序启动)并仍满足标准要求的时间点.
目前的C++ 20草案将填补这个漏洞并需要system_clock
使用Unix时间.换句话说,不知道当前时间的C++实现是不符合的.
这是标准委员会的疏忽吗?符合标准的C++实现如何表明它不知道当前的日期和时间?
(请注意,在标准的其它部分这一问题得到解决.例如,一个实现可以设置__TIME__
和__DATE__
宏来实现自定义的值,如果实际时间和日期不详).
请考虑以下代码:
#include<iostream>
template<class..., class... T>
int f(T...) { return 1; }
template<class... T>
int f(T...) { return 2; }
int main()
{
std::cout << f(1);
}
Run Code Online (Sandbox Code Playgroud)
它1
在gcc 8.2上编译和打印,但由于调用f(1)
不明确而无法在clang 7上编译.
如果调用被替换为f()
两个编译器都无法编译声称调用是不明确的.
如果参数包class... T
被以简单的参数替换class T
(和T...
与T
),二者编译器也要求歧义.
在第一个示例中,哪个编译器符合标准?我想这归结为功能模板的特定部分排序规则,还是以这种方式使用双参数包已经形成错误了?
编辑:
我的理解是双包本身并不是格式错误,因为我的阅读中的[temp.param] 17.1/15似乎明确允许这个,如果第二个包可以从函数参数中推导出来,这似乎是因为该T...
函数参数包.
也可以显式指定第一个参数包的参数,但不是第二个参数包的参数,因此并不总是(在模板参数推断之后)至少一个参数包为空.我不确定这是否会使程序格式不正确,因为我不知道在这种情况下如何阅读例如[temp.res] 17.7/8.3.
gcc和clang似乎都没有双参数包本身,例如当第二个函数模板重载被删除时,两个编译器都打印1
.但这可能是形成不良的情况,无需诊断.
此外,我假设使用类模板参数推导,可变参数类模板可以定义一个可变参数构造函数模板,这意味着构造函数候选类似于我的双参数包示例,据我所知,相同的重载决议和模板参数推导需要在这种情况下.这个问题是由另一个带有这样设置的问题所驱动的:Variadic类模板推导失败,使用gcc 8.2,编译clang和msvc 另请参阅讨论:使用可变参数模板构造函数的演绎指南和可变参数类模板 - 不匹配的参数包长度
现在我也找到了问题的演绎指南和可变参数模板的答案,我假设gcc是错误的并且调用应该被认为是模棱两可的,但我想让它验证这适用于这里同样的方式.我也会更加详细地欢迎推理,因为功能模板偏序规则对我来说似乎很不清楚.
c++ language-lawyer overload-resolution template-argument-deduction
考虑以下两个程序:
#include<variant>
#include<iostream>
constexpr auto f() {
using T = std::variant<bool, int>;
T t(false);
t = T(true);
return std::get<bool>(t);
}
template<auto V>
void print() { std::cout << V << "\n"; }
int main() {
print<f()>();
}
Run Code Online (Sandbox Code Playgroud)
和
#include<variant>
#include<iostream>
constexpr auto f() {
using T = std::variant<bool, int>;
T t(false);
t = T(42);
return std::get<int>(t);
}
template<auto V>
void print() { std::cout << V << "\n"; }
int main() {
print<f()>();
}
Run Code Online (Sandbox Code Playgroud)
海湾合作委员会汇编这两项并输出预期结果.在两种情况下,Clang都不会使用以下错误消息编译它们中的任何一个:
<source>:4:16: error: constexpr function never produces a …
Run Code Online (Sandbox Code Playgroud) 对于std::is_literal_type
和,这是相同的情况std::is_standard_layout
.
std::is_literal_type
在libc ++中的实现是
template <class _Tp> struct _LIBCPP_TEMPLATE_VIS is_literal_type
#ifdef _LIBCPP_IS_LITERAL
: public integral_constant<bool, _LIBCPP_IS_LITERAL(_Tp)>
#else
: integral_constant<bool, is_scalar<typename remove_all_extents<_Tp>::type>::value ||
is_reference<typename remove_all_extents<_Tp>::type>::value>
#endif
{};
Run Code Online (Sandbox Code Playgroud)
没有_LIBCPP_IS_LITERAL
,所以代码将是
template <typename T> struct is_literal_type : integral_constant<bool,
is_scalar<typename remove_all_extents<T>::type>::value or
is_reference<typename remove_all_extents<T>::type>::value> {};
Run Code Online (Sandbox Code Playgroud)
我写了一个演示:
#include <iostream>
using namespace std;
struct s {
int a;
char b;
long c;
};
int main(int argc, char *argv[]) {
cout << boolalpha;
cout << is_scalar_v<typename remove_all_extents<s>::type> << endl;
cout << is_reference_v<typename …
Run Code Online (Sandbox Code Playgroud) c++ ×4
c++17 ×2
c++-chrono ×1
c++20 ×1
constexpr ×1
libc++ ×1
std ×1
template-argument-deduction ×1
time ×1
variant ×1