模板编译时错误

turing-complete 2013-08-17 05:09:41
下面的代码中,有一行注释,取消这行注释就会出现编译时错误。
就是想不明白为什么,坐等码友解惑。
环境:GCC4.4.6 -std=c++0x

#include <iostream>
#include <iterator>
#include <string>

template<typename T>
struct has_const_iterator {
template<typename C> static char test(const typename C::const_iterator*);
template<typename C> static long test(...);
static const bool value = sizeof(test<T>(0)) == sizeof(char);
typedef T type;
};

template <typename T>
struct has_begin_end {
struct Dummy { typedef void const_iterator; };
typedef typename std::conditional<has_const_iterator<T>::value, T, Dummy>::type TCompatible;
typedef typename TCompatible::const_iterator TIter;

struct Fallback { TIter begin() const; TIter end() const; };
struct Derived : public TCompatible, public Fallback { };

template<typename C, C> struct TWapper;

template<typename C> static char b(TWapper<TIter (Fallback::*)() const, &C::begin>*);
template<typename C> static long b(...);
template<typename C> static char e(TWapper<TIter (Fallback::*)() const, &C::end>*);
template<typename C> static long e(...);

static bool const beg_value = sizeof(b<Derived>(0)) == sizeof(long);
static bool const end_value = sizeof(e<Derived>(0)) == sizeof(long);
};

template<typename T>
struct is_container {
static const bool value = has_const_iterator<T>::value &&
// !std::is_same<char, typename T::const_iterator::value_type>::value &&
has_begin_end<T>::beg_value && has_begin_end<T>::end_value;
};

int main(int argc, char* argv[]) {
std::cout << std::boolalpha << is_container<std::string>::value << std::endl;
}
...全文
236 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
ri_aje 2013-08-18
  • 打赏
  • 举报
回复
最后补充一点,instantiation 和 evaluating an expression 不一样,即便 && 的第一个表达式值为真,也只说明第二个表达式不用求值了,但是实例化还是必须的。
飞天御剑流 2013-08-18
  • 打赏
  • 举报
回复
第一个表达式为false,就不会对第二个表达式求值了。
ri_aje 2013-08-18
  • 打赏
  • 举报
回复
引用 9 楼 max_min_ 的回复:
[quote=引用 8 楼 ri_aje 的回复:] [quote=引用 7 楼 mougaidong 的回复:] 谢谢。 请教下兄台: 在编译时,若干个判断语句用 && 连接,不管第一个表达式true或者false,编译器都要对接下来的几个表达式继续求值,是这样的吗? [quote=引用 6 楼 ri_aje 的回复:] 啊,知道楼主说什么了。如果把注释打开,然后这么用就会出错了。

struct test_t { };
int main ()
{
  std::cout << std::boolalpha << is_container<test_t>::value << std::endl;
}
因为 test_t::const_iterator 不存在,所以 std::is_same 的第二个模板参数会出问题,导致编译错误。这种情况使用 traits 就行了,比如:

template <typename T, bool = has_const_iterator<T>::value>
struct value_type_traits
{
 using value_type = void; // dummy type when T has no const_iterator
};
template <typename T>
struct value_type_traits<T,true>
{
 using value_type = typename T::const_iterator::value_type;
};

template<typename T>
struct is_container {
  static const bool value = has_const_iterator<T>::value &&
      !std::is_same<char, typename value_type_traits<T>::value_type>::value &&
      has_begin_end<T>::beg_value && has_begin_end<T>::end_value;
};

struct test_t { };

int main ()
{
  std::cout << std::boolalpha << is_container<std::string>::value << std::endl;
  std::cout << std::boolalpha << is_container<std::vector<int>>::value << std::endl;
  std::cout << std::boolalpha << is_container<std::list<float>>::value << std::endl;
  std::cout << std::boolalpha << is_container<std::set<size_t>>::value << std::endl;
  std::cout << std::boolalpha << is_container<test_t>::value << std::endl;
}
[/quote] 是的,标准要求的。[/quote] 不是吧? 新标准要求? 我怎么记得这里是有个中断的呢?当前面一个为true才继续判断下一个呢?[/quote] 另外我猜你说的是 && expression,后者确实有短路求值的属性,不过那个是 runtime 行为,因此 14.7.1/5 在这里起主导作用。
ri_aje 2013-08-18
  • 打赏
  • 举报
回复
引用 9 楼 max_min_ 的回复:
[quote=引用 8 楼 ri_aje 的回复:] [quote=引用 7 楼 mougaidong 的回复:] 谢谢。 请教下兄台: 在编译时,若干个判断语句用 && 连接,不管第一个表达式true或者false,编译器都要对接下来的几个表达式继续求值,是这样的吗? [quote=引用 6 楼 ri_aje 的回复:] 啊,知道楼主说什么了。如果把注释打开,然后这么用就会出错了。

struct test_t { };
int main ()
{
  std::cout << std::boolalpha << is_container<test_t>::value << std::endl;
}
因为 test_t::const_iterator 不存在,所以 std::is_same 的第二个模板参数会出问题,导致编译错误。这种情况使用 traits 就行了,比如:

template <typename T, bool = has_const_iterator<T>::value>
struct value_type_traits
{
 using value_type = void; // dummy type when T has no const_iterator
};
template <typename T>
struct value_type_traits<T,true>
{
 using value_type = typename T::const_iterator::value_type;
};

template<typename T>
struct is_container {
  static const bool value = has_const_iterator<T>::value &&
      !std::is_same<char, typename value_type_traits<T>::value_type>::value &&
      has_begin_end<T>::beg_value && has_begin_end<T>::end_value;
};

struct test_t { };

int main ()
{
  std::cout << std::boolalpha << is_container<std::string>::value << std::endl;
  std::cout << std::boolalpha << is_container<std::vector<int>>::value << std::endl;
  std::cout << std::boolalpha << is_container<std::list<float>>::value << std::endl;
  std::cout << std::boolalpha << is_container<std::set<size_t>>::value << std::endl;
  std::cout << std::boolalpha << is_container<test_t>::value << std::endl;
}
[/quote] 是的,标准要求的。[/quote] 不是吧? 新标准要求? 我怎么记得这里是有个中断的呢?当前面一个为true才继续判断下一个呢?[/quote] c++03 14.7.1/4 && c++11 14.7.1/5 A class template specialization is implicitly instantiated if the class type is used in a context that requires a completely-defined object type or if the completeness of the class type might affect the semantics of the program.
max_min_ 2013-08-18
  • 打赏
  • 举报
回复
引用 8 楼 ri_aje 的回复:
[quote=引用 7 楼 mougaidong 的回复:] 谢谢。 请教下兄台: 在编译时,若干个判断语句用 && 连接,不管第一个表达式true或者false,编译器都要对接下来的几个表达式继续求值,是这样的吗? [quote=引用 6 楼 ri_aje 的回复:] 啊,知道楼主说什么了。如果把注释打开,然后这么用就会出错了。

struct test_t { };
int main ()
{
  std::cout << std::boolalpha << is_container<test_t>::value << std::endl;
}
因为 test_t::const_iterator 不存在,所以 std::is_same 的第二个模板参数会出问题,导致编译错误。这种情况使用 traits 就行了,比如:

template <typename T, bool = has_const_iterator<T>::value>
struct value_type_traits
{
 using value_type = void; // dummy type when T has no const_iterator
};
template <typename T>
struct value_type_traits<T,true>
{
 using value_type = typename T::const_iterator::value_type;
};

template<typename T>
struct is_container {
  static const bool value = has_const_iterator<T>::value &&
      !std::is_same<char, typename value_type_traits<T>::value_type>::value &&
      has_begin_end<T>::beg_value && has_begin_end<T>::end_value;
};

struct test_t { };

int main ()
{
  std::cout << std::boolalpha << is_container<std::string>::value << std::endl;
  std::cout << std::boolalpha << is_container<std::vector<int>>::value << std::endl;
  std::cout << std::boolalpha << is_container<std::list<float>>::value << std::endl;
  std::cout << std::boolalpha << is_container<std::set<size_t>>::value << std::endl;
  std::cout << std::boolalpha << is_container<test_t>::value << std::endl;
}
[/quote] 是的,标准要求的。[/quote] 不是吧? 新标准要求? 我怎么记得这里是有个中断的呢?当前面一个为true才继续判断下一个呢?
ri_aje 2013-08-18
  • 打赏
  • 举报
回复
引用 7 楼 mougaidong 的回复:
谢谢。 请教下兄台: 在编译时,若干个判断语句用 && 连接,不管第一个表达式true或者false,编译器都要对接下来的几个表达式继续求值,是这样的吗? [quote=引用 6 楼 ri_aje 的回复:] 啊,知道楼主说什么了。如果把注释打开,然后这么用就会出错了。

struct test_t { };
int main ()
{
  std::cout << std::boolalpha << is_container<test_t>::value << std::endl;
}
因为 test_t::const_iterator 不存在,所以 std::is_same 的第二个模板参数会出问题,导致编译错误。这种情况使用 traits 就行了,比如:

template <typename T, bool = has_const_iterator<T>::value>
struct value_type_traits
{
 using value_type = void; // dummy type when T has no const_iterator
};
template <typename T>
struct value_type_traits<T,true>
{
 using value_type = typename T::const_iterator::value_type;
};

template<typename T>
struct is_container {
  static const bool value = has_const_iterator<T>::value &&
      !std::is_same<char, typename value_type_traits<T>::value_type>::value &&
      has_begin_end<T>::beg_value && has_begin_end<T>::end_value;
};

struct test_t { };

int main ()
{
  std::cout << std::boolalpha << is_container<std::string>::value << std::endl;
  std::cout << std::boolalpha << is_container<std::vector<int>>::value << std::endl;
  std::cout << std::boolalpha << is_container<std::list<float>>::value << std::endl;
  std::cout << std::boolalpha << is_container<std::set<size_t>>::value << std::endl;
  std::cout << std::boolalpha << is_container<test_t>::value << std::endl;
}
[/quote] 是的,标准要求的。
turing-complete 2013-08-18
  • 打赏
  • 举报
回复
谢谢。 请教下兄台: 在编译时,若干个判断语句用 && 连接,不管第一个表达式true或者false,编译器都要对接下来的几个表达式继续求值,是这样的吗?
引用 6 楼 ri_aje 的回复:
啊,知道楼主说什么了。如果把注释打开,然后这么用就会出错了。

struct test_t { };
int main ()
{
  std::cout << std::boolalpha << is_container<test_t>::value << std::endl;
}
因为 test_t::const_iterator 不存在,所以 std::is_same 的第二个模板参数会出问题,导致编译错误。这种情况使用 traits 就行了,比如:

template <typename T, bool = has_const_iterator<T>::value>
struct value_type_traits
{
 using value_type = void; // dummy type when T has no const_iterator
};
template <typename T>
struct value_type_traits<T,true>
{
 using value_type = typename T::const_iterator::value_type;
};

template<typename T>
struct is_container {
  static const bool value = has_const_iterator<T>::value &&
      !std::is_same<char, typename value_type_traits<T>::value_type>::value &&
      has_begin_end<T>::beg_value && has_begin_end<T>::end_value;
};

struct test_t { };

int main ()
{
  std::cout << std::boolalpha << is_container<std::string>::value << std::endl;
  std::cout << std::boolalpha << is_container<std::vector<int>>::value << std::endl;
  std::cout << std::boolalpha << is_container<std::list<float>>::value << std::endl;
  std::cout << std::boolalpha << is_container<std::set<size_t>>::value << std::endl;
  std::cout << std::boolalpha << is_container<test_t>::value << std::endl;
}
turing-complete 2013-08-18
  • 打赏
  • 举报
回复
好的,谢谢。
引用 13 楼 ri_aje 的回复:
最后补充一点,instantiation 和 evaluating an expression 不一样,即便 && 的第一个表达式值为真,也只说明第二个表达式不用求值了,但是实例化还是必须的。
ri_aje 2013-08-17
  • 打赏
  • 举报
回复
啊,知道楼主说什么了。如果把注释打开,然后这么用就会出错了。

struct test_t { };
int main ()
{
  std::cout << std::boolalpha << is_container<test_t>::value << std::endl;
}
因为 test_t::const_iterator 不存在,所以 std::is_same 的第二个模板参数会出问题,导致编译错误。这种情况使用 traits 就行了,比如:

template <typename T, bool = has_const_iterator<T>::value>
struct value_type_traits
{
 using value_type = void; // dummy type when T has no const_iterator
};
template <typename T>
struct value_type_traits<T,true>
{
 using value_type = typename T::const_iterator::value_type;
};

template<typename T>
struct is_container {
  static const bool value = has_const_iterator<T>::value &&
      !std::is_same<char, typename value_type_traits<T>::value_type>::value &&
      has_begin_end<T>::beg_value && has_begin_end<T>::end_value;
};

struct test_t { };

int main ()
{
  std::cout << std::boolalpha << is_container<std::string>::value << std::endl;
  std::cout << std::boolalpha << is_container<std::vector<int>>::value << std::endl;
  std::cout << std::boolalpha << is_container<std::list<float>>::value << std::endl;
  std::cout << std::boolalpha << is_container<std::set<size_t>>::value << std::endl;
  std::cout << std::boolalpha << is_container<test_t>::value << std::endl;
}
ri_aje 2013-08-17
  • 打赏
  • 举报
回复
g++-4.8.0 没问题。
飞天御剑流 2013-08-17
  • 打赏
  • 举报
回复
楼主用了什么编译器?VS2012和g++都没有问题,应该是编译器对标准的支持有问题。
taodm 2013-08-17
  • 打赏
  • 举报
回复
倒,都2星级别了,还能问出这么有头无尾的问题。 啥编译错误啊? 还是去看看提问的智慧吧。
zhctj159 2013-08-17
  • 打赏
  • 举报
回复
使用g++ 4.7.3编译没有这个问题、莫非是语法支持的问题??
max_min_ 2013-08-17
  • 打赏
  • 举报
回复
有点复杂,下班先,明天看看!

65,210

社区成员

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

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