用于变量类型声明的C ++模板

时间:2015-02-23 18:35:53

标签: c++ templates instantiation

我有许多具有不同成员的类,所有类都具有以下类型的操作

::basedata::Maindata maindata;
::basedata::Subdata subinfo("This goes into the subinfo vector");
subinfo.contexts(contextInfo);
maindata.subdata().push_back(subinfo);

请注意,我在询问如何设置通用模板来执行这些操作。我无法为每种类型的maindata和subinfo设置特殊情况。我还需要能够看到如何从我的主代码中调用模板。我已经能够设置模板如果 maindata.subdata()存在,但如果模板不存在则继续在模板调用时遇到编译失败。那就是创建表单

的模板
perform_Push(maindata.subdata(), subinfo);

这样就可以编译maindata.subdata()是否存在。

我可以接受构建的模板,以便主代码可以显示

bool retval
retval = hasmember(maindata, subdata);
if (retval)
  {
    buildmember(maindata.subdata, subinfo);
    setAttributes(subinfo, data);
    perform_Push(maindata.subdata(), subinfo)
  }
else
  {
    // Perform alternate processing
   }

截至目前,当调用模板时,if中的代码将无法编译。

虽然:: basedata :: Maindata始终是定义的,但是:: basedata :: Subdata可能会也可能不会被定义,具体取决于我的代码正在构建的库的版本。 subdata被定义为属于maindata的向量,因此定义了push_back()操作。在任何情况下,有太多类型的子数据为模板中的每个类型创建一个单独的模板作为T :: Subdata。

也就是说,如果subdata是唯一的情况,我可以创建模板T的特殊化为:: maindata :: subdata和通用模板T.

我没有对包含文件或库的任何控制,因此我无法创建变量的#define以使用预编译器进行测试。有没有一种很好的方法来设置一个允许它工作的模板?我可以使用一个返回布尔值true(成功)或false(没有这样的定义)的模板,并在运行时调用备用处理。我不需要备用模板。

基本上,我问的是如何将SFINAE应用于这种特殊情况。

我已经设法弄清楚我需要做什么来设置基本模板

如果我有最基本的操作

maindata.subdata().push_back(data)

我可以定义表单的模板,

<template class T, typename D>
auto doPush(D data) -> decltype(T.pushback(data), void())
{
  T.push_back(data);
}

,电话会是

doPush<maindata.subdata()>(data);

然而,问题是当maindata还没有成员子数据时如何设置它。

2 个答案:

答案 0 :(得分:1)

您可以使用此模板获取一个布尔值,该值告诉您在泛型类型Subdata中是否存在成员类型T。仅当T是结构/类而不是命名空间时才有效。

#include <type_traits>

template <class T, class V = void>
  struct hasSubdata
  {
    enum { value = false }; 
  };

template <class T>
  struct hasSubdata<T, typename std::enable_if< std::is_same<typename T::Subdata, typename T::Subdata>::value >::type>
  {
    enum { value = true }; 
  };


struct basedata1
{
  struct Subdata {};
};

struct basedata2
{

};

#include <iostream>

int main ()
{
  std::cout << "basedata1: " << hasSubdata<basedata1>::value << std::endl;
  std::cout << "basedata2: " << hasSubdata<basedata2>::value << std::endl;
}

但是你不能使用普通的if,因为编译器会检查所有可能性的正确性。 你必须以类似的方式行事(非常难看):

template <class T, bool = hasSubdata<T>::value>
  struct SubdataUser
  {
    static void foo ()
    {
      std::cout << "I can use SubData member :)" << std::endl;

      typename T::Subdata subinfo ();
    }        
  };

template <class T>
  struct SubdataUser<T, false>
  {
    static void foo ()
    {
      std::cout << "I can not :(" << std::endl;
    }        
  };

int main ()
{
  SubdataUser<basedata1>::foo ();
  return 0;
}

不幸的是,据我所知,您不能拥有模板hasMember<Type,Member>::value,因为如果Member不存在,则编译失败。

但你可能想要这种类型的解决方案

#include <type_traits>
#include <iostream>

struct basedata1
{
  struct Subdata1 {};
  struct Subdata2 {};
  struct Subdata3 {};
};

struct basedata2
{
  struct Subdata1 {};
  //struct Subdata2 {};
  struct Subdata3 {};
};

template <class...>
  struct Require
  {
    enum { value = true };
  };

template <class T, bool = true>
  struct Impl
  {
    static void foo ()
    {
      std::cout << "At least one of the members required is not available :(" << std::endl;
    }        
  };

template <class T>
  struct Impl<T, Require< typename T::Subdata1,
                          typename T::Subdata2,
                          typename T::Subdata3 >::value >
  {
    static void foo ()
    {
      std::cout << "All members are available :)" << std::endl;

      typename T::Subdata2 my_var;
    }        
  };


int main( int argc, char* argv[] )
{
  Impl<basedata1>::foo ();
  Impl<basedata2>::foo ();
  return 0;
}

我希望这会有所帮助

答案 1 :(得分:0)

我已经设法弄清楚我需要做什么来设置基本模板以及成员模板。它实际上是两个不同的问题和两个不同的答案模板。它需要一个由特定成员模板调用的基本通用模板。

C++ preprocessor test if class member exists