LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1036|回复: 3

不知道是否g++的bug?(已解决)

[复制链接]
发表于 2005-12-21 13:21:58 | 显示全部楼层 |阅读模式
在使用Boost.Bind库时,发现如果使用构造函数创建临时变量再与bind绑定会出错。程序如下:

  1. #include <iostream>
  2. #include <string>
  3. #include <boost/bind.hpp>

  4. void print(const std::string& s)
  5. {
  6.         std::cout << s << std::endl;
  7. }

  8. int main()
  9. {
  10.         boost::bind(&print, _1)
  11.                 (std::string("Hello, world!"));
  12. }
复制代码

在编译时出现一下错误信息:
dxy@dengxy:~/Program$ g++ test.cc
test.cc: In function ‘int main()’:
test.cc:13: error: no match for call to ‘(boost::_bi::bind_t<void, void (*)(const std::string&), boost::_bi::list1<boost::arg<1> > >) (std::string)’
/usr/include/boost/bind/bind_template.hpp:17: note: candidates are: typename boost::_bi::result_traits<R, F>::type boost::_bi::bind_t<R, F, L>:perator()() [with R = void, F = void (*)(const std::string&), L = boost::_bi::list1<boost::arg<1> >]
/usr/include/boost/bind/bind_template.hpp:23: note:                 typename boost::_bi::result_traits<R, F>::type boost::_bi::bind_t<R, F, L>:perator()() const [with R = void, F = void (*)(const std::string&), L = boost::_bi::list1<boost::arg<1> >]
/usr/include/boost/bind/bind_template.hpp:29: note:                 typename boost::_bi::result_traits<R, F>::type boost::_bi::bind_t<R, F, L>:perator()(A1&) [with A1 = std::string, R = void, F = void (*)(const std::string&), L = boost::_bi::list1<boost::arg<1> >]
/usr/include/boost/bind/bind_template.hpp:35: note:                 typename boost::_bi::result_traits<R, F>::type boost::_bi::bind_t<R, F, L>:perator()(A1&) const [with A1 = std::string, R = void, F = void (*)(const std::string&), L = boost::_bi::list1<boost::arg<1> >]

如果使用bind的语句修改为:
boost::bind(&print, _1)("Hello, world!");
即不构造std::string临时变量,而是使用从const char*到std::string的隐式转换就没有问题。

这里想问一下:
1、源程序是否为合法的C++程序?
2、如果源程序合法,那么这个问题是否与libstdc++的string类实现方法有关?即是否产生了引用的引用错误?
3、除以上两点外,是否会由其他因素导致?
4、可否确定这是g++的bug?

此段代码在Debian sid的g++-4.0(g++ 4.0.3 20051201 prerelease)及MinGW(g++ 3.4.4)上测试编译,出现同样的错误。在Visual C++ 2005却编译通过。
发表于 2005-12-27 18:40:21 | 显示全部楼层
这涉及到C++里面的引用是否能够引用一个临时变量的问题,The cpp programming language 一书中提到,引用只能用于左值,临时变量显然不是左值,所以不能使用,实验一:
  1. [rick@Fedora-Core test]$ cat test.cc
  2. #include <string>
  3. #include <iostream>
  4. void print( int& s)
  5. {
  6.         std::cout<< s << std::endl;
  7. }
  8. int main()
  9. {
  10.         int a = 2;
  11.         print(a++);
  12.         print(++a);
  13. }
复制代码
第一个输出不能通过编译,第二个却可以,这充分说明了以上的观点.

那么我们来看一下那个bind做后调用的函数:
  1.      29     template<class A1> result_type operator()( A1 & a1)
  2.      30     {
  3.      31         list1< A1 &> a(a1);
  4.      32         BOOST_BIND_RETURN l_(type<result_type>(), f_, a, 0);
  5.      33     }
  6.      34
  7.      35     template<class A1> result_type operator()(A1 & a1) const
  8.      36     {
  9.      37         list1<A1 &> a(a1);
  10.      38         BOOST_BIND_RETURN l_(type<result_type>(), f_, a, 0);
  11.      39     }
复制代码
很明显,他需要一个引用作为参数,所以如果给了一个临时变量显然是通不过的.


然后.the cpp programming language 上又说了,如果是const T & 类型,却可以接受左值,甚至临时变量,那么究竟是不是呢? 我们再做一个实验,将上面的模板函数改一下:
  1.      29     template<class A1> result_type operator()(const A1 & a1)
  2.      30     {
  3.      31         list1<const  A1 &> a(a1);
  4.      32         BOOST_BIND_RETURN l_(type<result_type>(), f_, a, 0);
  5.      33     }
复制代码
现在再把你的测试程序拿来编译
  1. [rick@Fedora-Core test]$ cat test.cc
  2. #include <string>
  3. #include <iostream>
  4. #include <boost/bind.hpp>
  5. void print( const std::string& s)
  6. {
  7.         std::cout<< s << std::endl;
  8. }
  9. int main()
  10. {
  11.         bind(print,_1)(std::string("Hello"));
  12. }
  13. [rick@Fedora-Core test]$ g++ test.cc
  14. [rick@Fedora-Core test]$ ./a.out
  15. Hello
复制代码
ok,通过了.证明我们的想法是正确的.
回复 支持 反对

使用道具 举报

发表于 2005-12-27 18:42:21 | 显示全部楼层
btw: 那些模板函数在文件 /usr/include/boost/bind/bind_template.hpp 中
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-12-27 20:04:04 | 显示全部楼层
rickxbx兄实在高人,拜服!

补基础……
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表