2

我希望这段代码可以工作,但它无法用 GCC 编译。如果您将内部类取出,它会编译。

#include <algorithm>

template <typename T>
struct Outer
{
  struct Inner
  {
    int x;
  };
  Inner vec[3];
};

template <typename T>
bool operator <(const typename Outer<T>::Inner& lhs, const typename Outer<T>::Inner& rhs)
{
  return lhs.x < rhs.x;
}

int main()
{
  Outer<int> out;
  Outer<int>::Inner in;
  std::lower_bound(out.vec, out.vec + 3, in);
}

GCC 4.4 有这样的说法:

...
bits/stl_algo.h:2442: error: no match for ‘operator<’ in ‘* __middle < __val’

GCC 4.7 打印了更多的东西,包括上面的,以这个结尾:

...
bits/stl_algobase.h:957:4: note: couldn't deduce template parameter ‘T’

我愿意相信它不是格式良好的 C++,但为什么不呢?

4

4 回答 4

2

如果您超载特定operator<int问题将消失:

bool operator<(const typename Outer<int>::Inner& lhs, 
               const typename Outer<int>::Inner& rhs)
{
    return lhs.x < rhs.x;
}

 

更简单的解决方案是operator<在内部定义Inner

template<typename T>
struct Outer
{

    struct Inner
    {
        int x;

        bool operator<(const Inner& obj) const
        {
            return x < obj.x;
        }

    };
    Inner vec[3];
};

此外,这只是一个快速的解决方案。我的答案不是为什么编译器在模板模式下的嵌套情况下找不到operator<

于 2013-04-18T04:46:00.387 回答
2

这是另一种解决方法。为什么不使用自定义比较器?

template <typename T>
struct Comparer
{
    bool operator()(const typename Outer<T>::Inner& lhs, const typename Outer<T>::Inner& rhs)
    {
        return lhs.x < rhs.x;
    }
};

int main()
{
    Outer<int> out;
    Outer<int>::Inner in;
    std::lower_bound(out.vec, out.vec + 3, in, Comparer<int>());
}

希望这对你有用。

于 2013-04-18T05:55:47.693 回答
2

您提到的问题是编译器无法推断出模板参数T。这是因为 typename Outer::Inner 是 T 的非推导上下文上下文。

当模板参数仅在非推导上下文中使用时,模板参数推导不考虑它。详细信息在 C++ 标准 (2003) 的第 14.8.2.4 节。

为什么?如果您将 Outer 专业化为:

template <>
struct Outer<int>
{
   struct Inner
   {
       double y;
   };
   Inner vec[3];
}; 

编译器无法推断 Outer::Inner 是否应该引用此定义或前一个定义。

现在,到解决方案。有几个可能的解决方案:

  1. 将 operator< 移动到 Inner 内部并使其成为友元函数。
  2. 像M M.建议的那样在 Inner 中定义 operator< 。
  3. Johannes Schaub 建议 - litb:从由内部参数化的 CRTP 基础派生内部。然后将参数类型设为 CRTP 类,并将参数引用强制转换为派生的内部类,其类型由您推导出的模板参数给出。

我尝试了CRTP方法,因为它听起来很酷!:

template <typename Inner>
struct Base
{
};

template <typename T>
struct Outer
{
  struct Inner : Base<Inner>
  {
    T x;
  };
  Inner vec[3];
};

template <typename T>
bool operator< (const Base<T>& lhs, const Base<T>& rhs)
{
  return static_cast<const T&>(lhs).x < static_cast<const T&>(rhs).x;
}

相关答案:1、2、3 _ _

于 2013-04-29T20:49:34.223 回答
1

Mar0ux 的回答非常好。您可以在此处找到更多信息:

Stephan T. Lavavej: Core C++, 2 of n

您应该观看整个视频系列 - 它包含很多有用的信息,但您可能会从第 34 分钟左右开始回答您的问题。Stephen 提到了一个需要牢记的基本规则:

::是模板实参推演的砖墙,即T无法推演左侧的模板实参。

于 2013-04-30T13:21:08.920 回答