c++ 模板参数错误

fallening 2010-11-20 05:25:52
代码可以直接在 https://github.com/fengwang/random_variate_generator在线阅读
这样下载源代码:
git clone git://github.com/fengwang/random_variate_generator.git
然后
cd random_variate_generator && make binomial_test
错误如下:
g++ -c -O2 -Wall -g -std=c++0x -Iinclude  -o ./obj/binomial_test.o example/binomial_test.cc
example/binomial_test.cc: In function ‘int main()’:
example/binomial_test.cc:13:45: error: template argument 3 is invalid
example/binomial_test.cc:13:49: error: invalid type in declaration before ‘(’ token
example/binomial_test.cc:13:58: error: initializer expression list treated as compound expression
example/binomial_test.cc:13:58: warning: left-hand operand of comma has no effect
example/binomial_test.cc:16:14: error: request for member ‘begin’ in ‘vg’, which is of non-class type ‘int’
example/binomial_test.cc:16:26: error: request for member ‘begin’ in ‘vg’, which is of non-class type ‘int’
example/binomial_test.cc:18:31: error: request for member ‘begin’ in ‘vg’, which is of non-class type ‘int’
example/binomial_test.cc:18:43: error: request for member ‘begin’ in ‘vg’, which is of non-class type ‘int’
example/binomial_test.cc:18:59: error: unable to deduce ‘auto’ from ‘<expression error>’
make: *** [binomial_test.o] Error 1
gcc 4.5.1 编译错误信息如上,icc 11.1以及ms vc10均可通过。


实现的三个随机数引擎,其中mitchell_moore 和linear_congruential没有问题,就是结构几乎完全一致的mt19937出问题了。
...全文
1188 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
fallening 2010-11-21
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 hqin6 的回复:]

引用 9 楼 fallening 的回复:

引用 7 楼 hqin6 的回复:

引用 3 楼 fallening 的回复:

有人能够重现我这边的问题么?
假如以后gcc又出了一个gcc 4.6 禁用了模板这一技术,道士该如何?出家?

呵呵,不需要太完美。。。想做到每个编译器都支持,几乎不可能的。。。

一直在追新,虽然从gentoo退到archlinux了;
不过……
[/Quote]

是的,是的,见笑见笑了~~~~
太乙 2010-11-21
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 fallening 的回复:]

引用 7 楼 hqin6 的回复:

引用 3 楼 fallening 的回复:

有人能够重现我这边的问题么?
假如以后gcc又出了一个gcc 4.6 禁用了模板这一技术,道士该如何?出家?

呵呵,不需要太完美。。。想做到每个编译器都支持,几乎不可能的。。。

一直在追新,虽然从gentoo退到archlinux了;
不过 gcc 的版本都一直是最新的稳定版本,如果将gc……
[/Quote]
那个中文的帖子我看了,道士估计没看effective stl!那是语法解析的问题,但是跟你这不是一个问题啊。。。

至于那个英文的bug问题,不仅在4.5上,在4.4上也会有问题,还是语法有点儿小问题:
那个兄弟说的没错,一个临时变量不能做一个引用,而应该做一个const 引用----这个我不解释了吧?

道士有兴趣看看/usr/include/c++/4.4/bits/stream_iterator.h这个文件的164行:

155 typedef basic_ostream<_CharT, _Traits> ostream_type;



162 public:
163 /// Construct from an ostream.
164 ostream_iterator(ostream_type& __s) : _M_stream(&__s), _M_string(0) {}
165


这里确实没有const这样的关键字。。。。
fallening 2010-11-21
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 ri_aje 的回复:]
我用 g++-4.6.0 20101106 能够重现你的错误。虽然 g++ 给出的错误信息语焉不详,不过我认为 g++ 正确的拒绝了你的代码。你代码中的问题在于 name ambiguity,只不过刚好放在一个模板实例化的环境中,g++ 没能给出真正有用的排错信息。

具体而言,因为以下这一系列头文件包含,
vg.hpp -> vg/engine.hpp -> vg/engine/mt199……
[/Quote]

非常感谢,非常感谢。
fallening 2010-11-21
  • 打赏
  • 举报
回复
非常感谢,方才我看了一下 stl 的头文件,random 是这样辗转近来的:
algorithm -> bits/stl_algo.h -> random

在/usr/include/c++/4.5.1/bits/stl_algo.h 的65到67行,发现有:
#ifdef __GXX_EXPERIMENTAL_CXX0X__
#include <random> // for std::uniform_int_distribution
#endif


同样在这个文件的4150-4152行,可以看到实现shuffle的时候用到了std::uniform_int_distribution:
4150       typedef typename std::uniform_int_distribution<__ud_type> __distr_type;
4151 typedef typename __distr_type::param_type __p_type;
4152 __distr_type __d;


我只是偷懒用了一下c++0x 的auto,然后就把random 引进来了。而icc和msvc 没有出错,可能是因为它们的shuffle没有用到random
fallening 2010-11-21
  • 打赏
  • 举报
回复
非常感谢,方才我看了一下 stl 的头文件,random 是这样辗转近来的:
algorithm -> bits/stl_algo.h -> random

在bits/stl_algo.h 的65到67行,发现有:

#ifdef __GXX_EXPERIMENTAL_CXX0X__
#include <random> // for std::uniform_int_distribution
#endif

同样在这个文件的4150-4152行,可以看到实现shuffle的时候用到了std::uniform_int_distribution:
4150       typedef typename std::uniform_int_distribution<__ud_type> __distr_type;
4151 typedef typename __distr_type::param_type __p_type;
4152 __distr_type __d;


我只是偷懒用了一下c++0x 的auto,然后就把random 引进来了。



ri_aje 2010-11-21
  • 打赏
  • 举报
回复
后来又想了一下,这也不能算你代码的错误,因为 ambiguity 同时取决于 std::mt19937 是否可见,但你并没有显示的 #include <random>,而标准也没有明确规定 algorithm 是否要包含 random,有些版本的 g++ 能够编译,说明 algorithm 对 random 的包含是最近才加进来的,而其他编译器能够编译说明 algorithm 对 random 的包含不是必须的。也不明白 g++-4.6 的 algorithm 为什么要加 random,想来想去只有 std::random_shuffle 可能用的上了,可是我看了一下源码,他们还是用的 std::rand。无论如何,尽量少使用 using namespace xxx; 总是值得提倡的。
ri_aje 2010-11-21
  • 打赏
  • 举报
回复
我用 g++-4.6.0 20101106 能够重现你的错误。虽然 g++ 给出的错误信息语焉不详,不过我认为 g++ 正确的拒绝了你的代码。你代码中的问题在于 name ambiguity,只不过刚好放在一个模板实例化的环境中,g++ 没能给出真正有用的排错信息。

具体而言,因为以下这一系列头文件包含,
vg.hpp -> vg/engine.hpp -> vg/engine/mt19937.hpp,以及主程序中的 using namespace vg;
因此在 unqualified name lookup 过程中 vg::mt19937 是可见的,也就是你的 vg::mt19937 能够作为 variate_generator<int, binomial, mt19937> vg(200, 0.3); 中第三个模板参数的候选名字。很不幸的是,在 g++-4.6.0 的具体实现中 #include <algorithm> 同时也间接的 #include <random> 了,后者是 C++0x 中随机数的头文件,诸多随机数序列生成器中,其中就包含一个叫 std::mt19937 的typedef,更巧合的是你的主程序中也有 using namespace std; 这一句,因此这个 std::mt19937 也是上面模板实例化中第三个模板参数的候选名字。所以对于 mt19937 的 unqualified name lookup 失败,因为存在 ambiguity (vg::mt19937 和 std::mt19937)。解决方法很简单,你只需要明确说明要用vg::mt19937 即可,像这样

variate_generator<int, binomial, vg::mt19937> vg(200, 0.3);

楼主遭遇的问题是典型的名字空间污染问题,这也是为什么诸多专家建议,在相对大型的工程中,不要直接使用 using namespace xxx; 的原因,实际上 namespace 就是为了解决这种问题应运而生的,using namespace xxx; 无条件的破坏了这种保护机制,通常情况下,编译器应该能够给出正确的错误信息,不过在复杂的模板实例化环境里,看来目前的 g++-4.6.0 还是没有保障的。



fallening 2010-11-21
  • 打赏
  • 举报
回复
是mt19937就会产生问题
fallening 2010-11-21
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 gules 的回复:]

作者在大约4小时前发表了:a tiny change in binomal test to generate error 如下:
C/C++ code

int main()
12 12 {
13 - //variate_generator<int, binomial, mt19937> vg(200, 0.3);
14 - variate_……
[/Quote]

这是为了将随机数引擎从mitchell_moore 转换到 mt19937, mitchell_moore没有问题,mitchell就不成了
fallening 2010-11-20
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 hqin6 的回复:]

引用 3 楼 fallening 的回复:

有人能够重现我这边的问题么?
假如以后gcc又出了一个gcc 4.6 禁用了模板这一技术,道士该如何?出家?

呵呵,不需要太完美。。。想做到每个编译器都支持,几乎不可能的。。。
[/Quote]
一直在追新,虽然从gentoo退到archlinux了;
不过 gcc 的版本都一直是最新的稳定版本,如果将gcc 退回到4.4,估计整个系统要重新编译一次;

我现在担心的是另外一个问题: 我上次也碰到过类似的c++错误,一伙人讨论下来说是gcc 的错误,然后我去gcc 那边发了一个 bugreport,结果被一个家伙指出这种用法是错误的,所有通过这段代码的编译器都有问题。
帖子见这里,被鄙视的那个bug见这里

也就是说,现在我不确认是gcc错了,还是别的编译器错了。
上次我认为别的编译器是对的,而gcc 是错误的,结果恰好相反,这次有同样的担心。
太乙 2010-11-20
  • 打赏
  • 举报
回复
C++

Improved experimental support for the upcoming C++0x ISO C++ standard, including support for raw strings, lambda expressions and explicit type conversion operators.
When printing the name of a class template specialization, G++ will now omit any template arguments which come from default template arguments. This behavior (and the pretty-printing of function template specializations as template signature and arguments) can be disabled with the -fno-pretty-templates option.
Access control is now applied to typedef names used in a template, which may cause G++ to reject some ill-formed code that was accepted by earlier releases. The -fno-access-control option can be used as a temporary workaround until the code is corrected.
Compilation time for code that uses templates should now scale linearly with the number of instantiations rather than quadratically, as template instantiations are now looked up using hash tables.
Declarations of functions that look like builtin declarations of library functions are only considered to be redeclarations if they are declared with extern "C". This may cause problems with code that omits extern "C" on hand-written declarations of C library functions such as abort or memcpy. Such code is ill-formed, but was accepted by earlier releases.
Diagnostics that used to complain about passing non-POD types to ... or jumping past the declaration of a non-POD variable now check for triviality rather than PODness, as per C++0x.
In C++0x mode local and anonymous classes are now allowed as template arguments, and in declarations of variables and functions with linkage, so long as any such declaration that is used is also defined (DR 757).
Labels may now have attributes, as has been permitted for a while in C. This is only permitted when the label definition and the attribute specifier is followed by a semicolon—i.e., the label applies to an empty statement. The only useful attribute for a label is unused.
G++ now implements DR 176. Previously G++ did not support using the injected-class-name of a template base class as a type name, and lookup of the name found the declaration of the template in the enclosing scope. Now lookup of the name finds the injected-class-name, which can be used either as a type or as a template, depending on whether or not the name is followed by a template argument list. As a result of this change, some code that was previously accepted may be ill-formed because
The injected-class-name is not accessible because it's from a private base, or
The injected-class-name cannot be used as an argument for a template template parameter.
In either of these cases, the code can be fixed by adding a nested-name-specifier to explicitly name the template. The first can be worked around with -fno-access-control; the second is only rejected with -pedantic.
A new standard mangling for SIMD vector types has been added, to avoid name clashes on systems with vectors of varying length. By default the compiler still uses the old mangling, but emits aliases with the new mangling on targets that support strong aliases. Users can switch over entirely to the new mangling with -fabi-version=4 or -fabi-version=0. -Wabi will now warn about code that uses the old mangling.
The command-line option -ftemplate-depth-N is now written as -ftemplate-depth=N and the old form is deprecated.
Conversions between NULL and non-pointer types are now warned by default. The new option -Wno-conversion-null disables these warnings. Previously these warnings were only available when using -Wconversion explicitly.







-----------------------------

http://gcc.gnu.org/gcc-4.5/changes.html
太乙 2010-11-20
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 fallening 的回复:]

有人能够重现我这边的问题么?
[/Quote]假如以后gcc又出了一个gcc 4.6 禁用了模板这一技术,道士该如何?出家?

呵呵,不需要太完美。。。想做到每个编译器都支持,几乎不可能的。。。
luciferisnotsatan 2010-11-20
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 hqin6 的回复:]

引用 2 楼 fallening 的回复:

gcc 4.5.1 gcc 4.6.0 都不成
道士不要再钻牛角尖了,要想知道,得看gcc 4.5+以后的版本在模板支持上作出了什么改变!可能有些特性不能用了。。。。

可以在make的时候加上依赖,检测gcc版本,必须<4.5+
[/Quote]
+1
太乙 2010-11-20
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 fallening 的回复:]

gcc 4.5.1 gcc 4.6.0 都不成
[/Quote]道士不要再钻牛角尖了,要想知道,得看gcc 4.5+以后的版本在模板支持上作出了什么改变!可能有些特性不能用了。。。。

可以在make的时候加上依赖,检测gcc版本,必须<4.5+
gules 2010-11-20
  • 打赏
  • 举报
回复
作者在大约4小时前发表了:a tiny change in binomal test to generate error 如下:

int main()
12 12 {
13 - //variate_generator<int, binomial, mt19937> vg(200, 0.3);
14 - variate_generator<int, binomial> vg(200, 0.3);
13 + variate_generator<int, binomial, mt19937> vg(200, 0.3);
14 + //variate_generator<int, binomial> vg(200, 0.3);
15 15
16 16 copy( vg.begin(), vg.begin()+1000, ostream_iterator<int>(cout, "\n"));
……
fallening 2010-11-20
  • 打赏
  • 举报
回复
有人能够重现我这边的问题么?
fallening 2010-11-20
  • 打赏
  • 举报
回复
gcc 4.5.1 gcc 4.6.0 都不成
太乙 2010-11-20
  • 打赏
  • 举报
回复
gcc version 4.4.5

no problem

64,670

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧