C ++ - 模板is_Pointer似乎失败的奇怪案例

时间:2016-11-28 13:28:38

标签: c++ c++11 templates template-meta-programming

我正在尝试为BinaryTree Operations创建项目,以下是带有代码的类原型,我遇到了问题。

BinaryTree.h文件中的BinaryTree类

template <class T>
class BinaryTree
{
   public:  
       BinaryTree();
       BinaryTree(T);     
};

BinaryTree.cpp中的构造函数实现

template<class T>
struct isPointer
{
  static const bool value=false;
};

template<class T>
struct isPointer<T*>
{
  static const bool value=true;
};

template<class T>
BinaryTree<T>::BinaryTree():root(nullptr)
{
  //ctor
}

template<class T>
BinaryTree<T>::BinaryTree(T data)
{
  if(isPointer<T>::value == true)
  {
   if(data != nullptr)
   {
      //Do something
   }
  }      
}

BinaryTreeOperations类继承BinaryTree类,其原型在BinaryTreeOperations.h中定义

template<class T>
class BinaryTreeOperations:public BinaryTree<T>
{
  public:

  //Constructors
  BinaryTreeOperations();
  BinaryTreeOperations(T);
};

虽然构造函数是在BinaryTreeOperations.cpp类中定义的

template<class T>
BinaryTreeOperations<T>::BinaryTreeOperations(T data):BinaryTree<T>(data)
{
  //ctor
}

Main.cpp文件中的主要功能

int main()
{
  cout << "Hello world!" << endl;

  BinaryTreeOperations<std::string> b("1");
}

现在g ++抛出的错误是

  

与'operator!='不匹配(操作数类型为   'std :: __ cxx11 :: basic_string'和'std :: nullptr_t')

在第

if(data != nullptr)
在BinaryTree.cpp类中定义的BinaryTree构造函数中的

问题就出现了。我已经定义了isPointer结构来检查给定的模板是否是指针。但看起来,尽管T是std :: string g ++正在进入if(isPointer<T>::value == true) 条件。

我不明白我做错了什么?任何形式的指导都将深受赞赏。

3 个答案:

答案 0 :(得分:2)

  if(isPointer<T>::value == true)
  {
   if(data != nullptr)
   {
      //Do something
   }
  }      

这将为每个T编译。即使对于给定的T,表达式isPointer<T>::value将评估为false,但整个事情将被编译。如果dataT的实例无法与nullptr进行比较,则会导致编译失败。

C ++ 17引入了static_if,这是一个编译时指令,它根据编译时constexpr选择性地编译代码块(本身就是一个有点引起争议的补充)。在C ++ 17之前,除了isPointer的特化之外,正确执行此操作的唯一方法是使用特化来有选择地编译这一块代码。

但是,无论如何,编译错误的答案是它等同于:

std::string data;

if (0)
{
   if (data != nullptr)
   {
      // ...
   }
}

有问题的代码永远不会到达的事实并没有改变它必须是有效的,可编译的C ++代码这一事实。

答案 1 :(得分:2)

这是constexpr if(C ++ 17)一个很好的补充:你的分支将在编译时评估你传递的每个T

可能的解决方法是利用enable_if并根据isPointer谓词的结果定义两个构造函数版本,并让SFINAE完成其工作

template <class T>
class BinaryTree
{
public:
  BinaryTree();

  template<typename TT = T>
  BinaryTree(TT, typename std::enable_if<!isPointer<TT>::value>::type * = nullptr) {

  }

  template<typename TT = T>
  BinaryTree(TT data, typename std::enable_if<isPointer<TT>::value>::type * = nullptr) {
    if (data != nullptr)
    {
      //Do something (this is a pointer)
    }
  }

};

Example

或者重构您的代码,记住模板完全是模板的事实,并且在实例化时,它将在任何它定义的代码分支。

答案 2 :(得分:1)

  

但看起来,尽管T是std :: string g ++正处于if(isPointer<T>::value == true)状态。

事实上。整个函数将被编译。执行能否达到这种比较是无关紧要的。

解决方案:编写一个函数模板并将其重载为指针。

template<class T>
void do_something(const T&) {
    // do nothing
}

template<class T>
void do_something(T* data) {
    if(data != nullptr) {
        // do something
   }
}

//  ...

template<class T>
BinaryTree<T>::BinaryTree(T data)
{
  do_something(data);
}

C ++ 17计划引入constexpr if,这将允许您在单个函数中就地编写条件编译时间。