请参见以下代码:
#include <utility>
struct A {
A(int, int) {}
};
struct tag {};
template <class... Args>
struct is_noexcept {
static constexpr bool value = noexcept(A{std::declval<Args>()...});
};
struct B : A {
//#1
template <class... Args>
B(tag, Args&&... args) noexcept(/*Here*/is_noexcept<Args...>::value) :
A{std::forward<Args>(args)...} {}
//#2
B(int x, int y) : A{x, y} {}
};
int main()
{
B x{0, 0};
}
此代码似乎已被GCC / Clang接受,但MSVC 2017拒绝了它。
似乎MSVC编译器在了解#1不是适当的重载之前(由于tag
和int
之间不兼容),尝试计算noexcept指定符,因此应将其丢弃。因此,它尝试评估is_noexcept<int>::value
并发现noexcept(A{std::declval<int>()})
格式错误。由于这不是在立即发生的情况下发生的,所以SFINAE并不是在这里出现的,所以很难出错。
(实际上,我对此不太确定,但是我已经确认,如果我在noexcept(A{std::declval<Args>()...})
处放置is_noexcept<Args...>::value
而不是/*Here*/
来使故障立即在上下文中,MSVC编译器愉快地删除了#1并调用了#2。对吗?)
我怀疑GCC / Clang是正确的,而MSVC是错误的,但是哪一个是正确的?
答案 0 :(得分:5)
这是MSVC错误。由于CWG 1330在[except.spec]/13中的规则是:
在以下情况下,认为需要 一个异常规范
- 在表达式中,该函数是唯一的查询结果或一组重载函数([basic.lookup],[over.match],[over.over])的选定成员;
- 该函数是odr使用的,或者,如果它出现在未求值的操作数中,则如果该表达式可能被求值,则将被使用;
- 将异常规范与另一个声明(例如,显式专门化或覆盖的虚函数)的规范进行比较;
- 函数已定义;或
- 调用默认函数的默认特殊成员函数需要异常规范。 [注:默认声明不需要对派生函数的隐式异常规范进行评估,而需要评估基本成员函数的异常规范,但是显式的noexcept-specifier需要隐式异常规范比较。 -注释]
仅在需要时才如上所述评估默认特殊成员函数的异常规范;类似地,仅在需要时才实例化功能模板或类模板的成员函数的专业化的 noexcept-specifier 。
不需要#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include <sys/time.h>
#include <math.h>
#include <string>
#include <cstdlib>
#define N ((cols+1)*rows + cols)
int main(int argc, char *argv[])
{
int fdr, fdw;
FILE *ftime_rw;
FILE *fp;
FILE *U, *V, *RI;
int rc, donebytes;
int *tologic, *fromlogic;
pid_t pid;
int i,j;
struct timeval tv1, tv2;
double time_rw;
char *buf;
int temp;
int rows= 575;
int cols= 18689;
fdr = open("/dev/xillybus_read_32", O_RDONLY);
fdw = open("/dev/xillybus_write_32", O_WRONLY);
if ((fdr < 0) || (fdw < 0))
{
perror("Failed to open Xillybus device file(s)");
exit(1);
}
U = fopen("U.txt", "r");
V = fopen("V.txt", "r");
RI = fopen("RI.txt", "a");
if(U==NULL || V==NULL || RI==NULL )
{
printf("Write in their respective files!\n");
exit(1);
}
for (i=0; i<rows; i++) // Read
{
fscanf(U,"%d", &temp);
fprintf(RI,"%d\n", temp);
}
for(j=0; j<rows; j++)
{
for (i=0; i<cols; i++) // Read
{
fscanf(V,"%d", &temp);
fprintf(RI,"%d ", temp);
}
fclose(U);
fclose(V);
fclose(RI);
tologic = (int*)malloc(sizeof(int)* N);
if (!tologic)
{
fprintf(stderr, "failed to allocate memory\n");
exit(1);
}
RI = fopen("RI.txt", "r");
for(j=0; j<rows; j++)
{
for (i=0; i<cols; i++)
fscanf(RI,"%d", &tologic[N]);
fclose(RI);
pid = fork(); // writer + reader
if (pid < 0)
{
perror("Failed to fork()");
exit(1);
}
if (pid) // writer process
{
close(fdr);
buf = (char *)tologic;
donebytes=0;
gettimeofday(&tv1, NULL); // start count time
while (donebytes < sizeof(int)*N) // write N integers
{
rc = write(fdw, tologic + donebytes, sizeof(int)*N - donebytes);
if ((rc < 0) && (errno == EINTR))
continue;
if (rc <= 0)
{
perror("write() failed");
exit(1);
}
donebytes += rc;
}
gettimeofday(&tv2, NULL); // stop count time
time_rw = (double) (tv2.tv_usec-tv1.tv_usec);
printf("Writer. Total time = %f usec\n", time_rw);
if(close(fdw)==-1)
printf("ERROR closing write_32 file!\n");
return 0;
}
else // reader process
{
close(fdw);
fromlogic =(int*)malloc(sizeof(int)* N);
if (! fromlogic)
{
fprintf(stderr, "failed to allocate memory\n");
exit(1);
}
buf = (char *)fromlogic;
donebytes = 0;
donebytes = 0;
gettimeofday(&tv1, NULL); // start count time
while (donebytes < sizeof(int)*rows) // read num_rows integers
{
rc = read(fdr, fromlogic + donebytes, sizeof(int)*rows - donebytes);
if ((rc < 0) && (errno == EINTR))
continue;
if (rc < 0)
{
perror("read() failed");
exit(1);
}
if (rc == 0)
{
fprintf(stderr, "Reached read EOF!? Should never happen.\n");
exit(0);
}
donebytes += rc;
}
gettimeofday(&tv2, NULL); // stop count time
time_rw = (double) (tv2.tv_usec-tv1.tv_usec);
printf("Reader. Total time = %f usec\n", time_rw);
for (i=0; i<rows; i++) // Integers read from logic
printf("Reader process : %d\n", fromlogic[i]);
sleep(1); // Let debug output drain (if used)
if(close(fdr)==-1)
printf("ERROR closing read_32 file!\n");
return 0;
}
}
}
}
的异常说明(我们不满足任何这些要求),因此不应实例化它。
还请注意,异常规范中的替换失败不是立即上下文的一部分,并且不是SFINAE友好的错误。