【问题标题】:Why SFINAE results in compiler error where it should have worked?为什么 SFINAE 会导致它应该工作的编译器错误?
【发布时间】:2011-07-05 17:17:33
【问题描述】:

我试图实现一个元程序,它会发现给定的指针类型是否为const。即

  • is_const<TYPE*>::value 应该是 false
  • is_const<const TYPE*>::value 应该是 true

以下是代码:

template<class TYPE>
struct is_const
{
  typedef char yes[3];
  template<typename T>
  struct Perform
  {
    static yes& check (const T*&);
    static char check (T*&);
  };  

  TYPE it; 
  enum { value = (sizeof(Perform<TYPE>::check(it)) == sizeof(yes)) };  
};

并且编译器错误信息是:

In instantiation of ‘is_const<int*>’:
instantiated from here
error: no matching function for call to ‘is_const<int*>::Perform<int*>::check(int*&)’
note: candidates are: static char (& is_const<TYPE>::Perform<T>::check(const T*&))[3] [with T = int*, TYPE = int*]
note: static char is_const<TYPE>::Perform<T>::check(T*&) [with T = int*, TYPE = int*]

我的注意力已转移到错误消息上。如果你看到最后一行:

note: static char is_const<TYPE>::Perform<T>::check(T*&) [with T = int*, TYPE = int*]

如果我们真的替换了T = int*TYPE = int*,那么它确实应该匹配适当的函数(char check())。我很想知道这里出了什么问题。

【问题讨论】:

  • 如果Tint *,那么T *&amp;int **&amp;。所以我认为签名不匹配......
  • @iammilind:不,应该不匹配,你有void foo( int **&amp; )int *p; foo( p );p是指向int的指针,而不是指向int的指针。

标签: c++ templates compiler-errors sfinae


【解决方案1】:

为什么这么迂回?一个直截了当的特质类怎么样:

#include <functional>

template <typename T> struct is_const_ptr : std::false_type { };
template <typename T> struct is_const_ptr<const T *> : std::true_type { };

struct Foo {};

int main()
{
  std::cout << is_const_ptr<Foo*>::value << is_const_ptr<const Foo*>::value << std::endl;
}

【讨论】:

  • +1,即使在问题中不清楚他要检查的是什么,在指针的情况下外部类型或指向的类型是否是 const ......我将从专业化中删除 *...
  • @Dribeas:就is_const?但是我们正在测试“pointer-to-const-T”,而不是“const pointer-to-T”...
  • 这就是我投票的原因,因为这个答案很明确:is_const_ptr 非常明确。
  • @Dribeas:是的,但是你怎么能从专业化中删除 * 并保留对“pointer-to-const”的检查?
  • 有时人们不得不同意不同意。在我们的案例中,我们在协议中存在分歧。我之前应该更清楚,所以我现在要更加努力,我的问题不是你的答案,而是他调用模板is_const但实际上测试is_const_ptr的问题。我之前想说的是,我会选择 name is right, implementation is wrong 方法(即实现is_const
【解决方案2】:

这是你的问题:

static yes& check (const T*&);
static char check (T*&);

当您实例化is_const&lt;int*&gt; 时,您的函数定义将扩展为:

static yes& check (const int**&);
static char check (int**&);

但是,您的临时项目 (TYPE it) 的类型为 int*,就像您指定的那样。您需要更改 check 函数签名以删除指针说明符,如下所示:

static yes& check (const T&);
static char check (T&);

【讨论】:

  • 我已经尝试过这种修改,但它似乎仍然不起作用。查看ideone.com/fMlxb的输出
【解决方案3】:

您的代码中有两处错误。

首先,以下

static yes& check (const T*&);
static char check (T*&);

必须改为

static yes& check (const T&);
static char check (T&);

第二个,it 成员必须是static

static TYPE it;

或者,只需将((TYPE)0) 传递给您的检查功能。不需要会员。

【讨论】:

  • +1 (sizeof(Perform&lt;TYPE&gt;::check((TYPE)0)) 将在编译时进行评估。
  • 如果它也是check(it)@VJo,它将在编译时进行评估。
  • 我已经尝试过这种修改,但它似乎仍然不起作用。查看ideone.com/fMlxb的输出
猜你喜欢
  • 2020-04-26
  • 2016-05-13
  • 2019-11-18
  • 2011-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多