以下皆为在开发我的 C++ 库 donnylib 的时候遇到的问题。 (一天遇到这么多 weird problems 也是很走运了)
donnylib : https://github.com/Donny-Hikari/donnylib
Weird Template Subclass
如下的程序会导致无法自动推断模板类型。(编译环境: g++ 5.4.0, -std=c++17)
template<class T>
struct FOO
{
struct NOT
{
NOT() { }
};
FOO() { sizeof(T); }
};
template<class T>
typename FOO<T>::NOT foo(typename FOO<T>::NOT a)
{
return a;
}
void test1()
{
FOO<int>::NOT f;
foo(f); // template argument deduction/substitution failed.
}
加上下面的代码也是不行的。
template<class T>
using NOT = typename FOO<T>::NOT;
template<class T>
NOT<T> foo(NOT<T> a)
{ return a; }
template<>
NOT<int> foo<int>(NOT<int> a);
void test1()
{
NOT<int> f;
foo(f);
}
只要是模板类的子类就会导致这样的问题。但是实际上还是可以推断出来的。当然手动特化还是可以的。不是模板类的子类也可以正常推断。
这其实是在做自己的库 donnylib 的时候遇到的问题。(不做库一般也不会有这样的问题。)最后是把子类提出来单独做模板类。
不知道标准协会什么时候会修复这个BUG. :-D 查了一下,其实这个问题多年前就有人提出来了。不过确实没有好的解决方法。只能把子类提出来放在外面,可是这样就会损失子类优势,比如交叉调用或访问。(虽然可以降低耦合度)
fwprintf 和 fwrite 调用冲突
猜猜下面代码的输出?
void test3()
{
fwprintf(stdout, L"fwprintf: Hello\n");
fwrite("fwrite: Hello\n", sizeof(char), 14, stdout);
putc('?', stdout);
}
正常都以为会是:
fwprintf: Hello
fwrite: Hello
?
实际上是
$ make build run
g++ main.cpp -o ./main -std=c++17
./main
fwprintf: Hello
一旦调用了 fwprintf 后面就没法用 fwrite, putc 等输出了。
调换顺序会怎么样呢?
void test3()
{
fwrite("fwrite: Hello\n", sizeof(char), 14, stdout);
putc('?', stdout);
fwprintf(stdout, L"fwprintf: Hello\n");
}
输出为:
$ make build run
g++ main.cpp -o ./main -std=c++17
./main
fwrite: Hello
?
fwprintf 也无法输出了。
用 fflush 也不行。
编译环境是 Ubuntu 16.04 4.4.0-116-generic, g++ 5.4.0 -std=c++17.
之后再详细调查一下。
在 Window 8.1, Visual Studio 2015 下测试,一切正常。
看来还有可能是系统调用的锅。
又试了下,发现不同文件不相互影响。推测是标志,缓冲区的问题。
逗号表达式的调度顺序和返回值
int f0() { printf("f0\n"); return 0; }
int f1() { printf("f1\n"); return 1; }
int fun1() { return f0(), f1(); }
int fun2() { return (f0(), f1()); }
void test2()
{
int a, b;
a = f0(), f1();
donny::logstdout << "a = f0(), f1() : " << a << donny::endl;
b = (f0(), f1());
donny::logstdout << "b = (f0(), f1()) : " << b << donny::endl;
donny::logstdout << "fun1 return f0(), f1() : " << fun1() << donny::endl;
donny::logstdout << "fun2 return (f0(), f1()) : " << fun2() << donny::endl;
}
output :
$ make build run
g++ main.cpp -o ./main -std=c++17
./main
f0
f1
[Tue Apr 03 07:27:37 2018]a = f0(), f1() : 0
f0
f1
[Tue Apr 03 07:27:37 2018]b = (f0(), f1()) : 1
f0
f1
[Tue Apr 03 07:27:37 2018]fun1 return f0(), f1() : 1
f0
f1
[Tue Apr 03 07:27:37 2018]fun2 return (f0(), f1()) : 1
a = f0(), f1() 其实是 (a = f0()), f1()
其他的都是 (f0(), f1())
逗号表达式的结果是最后一个(最右)的值。