C++ C++;-奇怪的情况是,模板是\u指针似乎失败了

C++ C++;-奇怪的情况是,模板是\u指针似乎失败了,c++,c++11,templates,template-meta-programming,C++,C++11,Templates,Template Meta Programming,我正在尝试为BinaryTree操作创建项目,下面是带有代码的类原型,我在其中遇到了问题 BinaryTree.h文件中的BinaryTree类 template <class T> class BinaryTree { public: BinaryTree(); BinaryTree(T); }; 在BinaryTree.cpp类中定义的BinaryTree构造函数中 template<class T> BinaryTr

我正在尝试为BinaryTree操作创建项目,下面是带有代码的类原型,我在其中遇到了问题

BinaryTree.h文件中的BinaryTree类

template <class T>
class BinaryTree
{
   public:  
       BinaryTree();
       BinaryTree(T);     
};
在BinaryTree.cpp类中定义的BinaryTree构造函数中

template<class T>
BinaryTreeOperations<T>::BinaryTreeOperations(T data):BinaryTree<T>(data)
{
  //ctor
}
问题来了。我已经定义了isPointer结构来检查给定模板是否为指针。但是看起来,尽管T是std::string,g++在
if(isPointer::value==true)
条件

我不明白我做错了什么?我们将非常感谢任何形式的指导

  if(isPointer<T>::value == true)
  {
   if(data != nullptr)
   {
      //Do something
   }
  }      
<> P>一个事实,即代码永远不会达到,它不会改变它必须是有效的,可编译的,C++代码的事实。 但是看起来,尽管T是std::string,g++仍处于
if(isPointer::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);
}
模板
void do_某事(const T&){
//无所事事
}
模板
void do_something(T*数据){
如果(数据!=nullptr){
//做点什么
}
}
//  ...
模板
二进制树::二进制树(T数据)
{
做某事(数据);
}

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

对于这种情况,(C++17)将是一个很好的补充:您的分支将在编译时对通过的每个T进行评估

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

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)
    }
  }

};
模板
类二叉树
{
公众:
二叉树();
模板
二进制树(TT,typename std::enable_if::value>::type*=nullptr){
}
模板
二进制树(TT数据,typename std::enable_if::type*=nullptr){
如果(数据!=nullptr)
{
//做点什么(这是一个指针)
}
}
};


或者重构你的代码,记住一个模板就是一个模板,当它被实例化时,它将为它定义的任何代码分支上的参数生成代码。

如果
是严格的运行时检查,两个分支都必须正确编译,即使其中一个已失效。@Bathsheba将使用std::is_pointer给我一个不同的结果。是:两个重载,一个用于指针,一个用于非指针,使用调度。的可能重复。考虑使用重载,因为@ Quentin suggestedYou也应该查看如果(0)表示错误。你的意思是如果(1)。还有任何关于这个可怕错误的建议。不,我特别指的是
if(0)
,问题中导致编译错误的同等情况,当
T
std::string
时会发生编译错误。另外,我也不会确切地称之为“可怕”错误。模板实例化的一个相当常见、神秘的方面经常被误解。谢谢。@Quentin先生在问题的评论中提到了使用std::enable_if进行调度。我从来没有使用过enable_,如果你能用同样的方法指导我一点。@Dr.Xperience你不一定需要
enable_if
,在这种情况下,它只会让这个程序稍微冗长一些。然而,如果您使用的是一个更复杂的特征条件,您的
isPointer
,那么避免重复多个专门化是很有用的。我建议您看看stackoverflow的现有答案,了解如何使用它。感谢bro提供了使用enable_if的解决方案。我不熟悉enable_if的概念。现在我想标记两个解决方案作为我问题的答案。在接受字符串文本的函数上使用此函数时,我面临一个奇怪的问题<代码>模板无效测试(TT数据){std::coutOh我得到了它我应该做
无效测试(T数据)
而不是
无效测试(TT数据)
我的错误。
if(data != nullptr)
  if(isPointer<T>::value == true)
  {
   if(data != nullptr)
   {
      //Do something
   }
  }      
std::string data;

if (0)
{
   if (data != nullptr)
   {
      // ...
   }
}
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);
}
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)
    }
  }

};