Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何有效地实现std::tuple,使空类型的tuple本身就是空类型?_C++_Templates_C++11_Tuples - Fatal编程技术网

C++ 如何有效地实现std::tuple,使空类型的tuple本身就是空类型?

C++ 如何有效地实现std::tuple,使空类型的tuple本身就是空类型?,c++,templates,c++11,tuples,C++,Templates,C++11,Tuples,我正在实现std::tuple,我希望它在对象大小和编译时间方面都尽可能高效。我正在遵循所提出的建议和建议 为了提高编译时性能,该实现不使用递归继承,而是使用具有tuple\u-leaf技巧的多重继承。此外,它在可能的情况下使用空基类优化来减少类型的大小 为了确保始终应用空基类优化,我的tuple本身的实现是从基类派生的,而不是将实现存储在成员变量中。但是,这会导致嵌套元组出现问题,因为tuple\u leaf技术通过转换到基类来工作。嵌套元组会导致歧义,因为同一类型的tuple\u leaf可

我正在实现
std::tuple
,我希望它在对象大小和编译时间方面都尽可能高效。我正在遵循所提出的建议和建议

为了提高编译时性能,该实现不使用递归继承,而是使用具有
tuple\u-leaf
技巧的多重继承。此外,它在可能的情况下使用空基类优化来减少类型的大小

为了确保始终应用空基类优化,我的
tuple
本身的实现是从基类派生的,而不是将实现存储在成员变量中。但是,这会导致嵌套元组出现问题,因为
tuple\u leaf
技术通过转换到基类来工作。嵌套元组会导致歧义,因为同一类型的
tuple\u leaf
可能在派生链中出现多次

下面是一个简化问题的程序。有没有一种简单的方法来消除转换的歧义,并允许程序在不抛出断言的情况下编译和执行?我曾考虑过检测嵌套的元组大小写,并以某种方式在其类型中编码每个
tuple\u leaf
的多维位置,但这似乎很复杂,可能会降低编译时性能

#include <type_traits>
#include <cassert>

template<int i, class T, bool = std::is_empty<T>::value>
struct tuple_leaf
{
  tuple_leaf(T x) : val(x) {}

  T& get() { return val; }

  T val;
};


template<int i, class T>
struct tuple_leaf<i,T,true> : private T
{
  tuple_leaf(T x) : T(x) {}

  T& get() { return *this; }
};


template<int i, class T1, class T2>
struct type_at
{
  using type = T1;
};


template<class T1, class T2>
struct type_at<1,T1,T2>
{
  using type = T2;
};


template<class T1, class T2>
struct tuple_base : tuple_leaf<0,T1>, tuple_leaf<1,T2>
{
  tuple_base(T1 a, T2 b) : tuple_leaf<0,T1>(a), tuple_leaf<1,T2>(b) {}

  template<int i>
  tuple_leaf<i,typename type_at<i,T1,T2>::type> get_leaf()
  {
    // XXX how to disambiguate this conversion?
    return *this;
  }
};


// XXX deriving from tuple_base rather than
//     making tuple_base a member is the root of the issue
template<class T1, class T2>
struct my_tuple : tuple_base<T1,T2>
{
  my_tuple(T1 a, T2 b) : tuple_base<T1,T2>(a, b) {}
};

template<int i, class T1, class T2>
typename type_at<i,T1,T2>::type& get(my_tuple<T1,T2>& t)
{
  return (t.template get_leaf<i>()).get();
}

template<class T1,class T2>
my_tuple<T1,T2> make_tuple(T1 a, T2 b)
{
  return my_tuple<T1,T2>(a,b);
}

struct empty {};

int main()
{
  auto tuple = make_tuple(empty(), make_tuple(empty(),empty()));

  assert((std::is_empty<decltype(tuple)>::value));
  assert(sizeof(tuple) == sizeof(empty));

  get<0>(tuple);

  return 0;
}
#包括
#包括
模板
结构元组
{
元组_叶(tx):val(x){}
T&get(){return val;}
T值;
};
模板
结构元组_叶:私有T
{
元组_叶(tx):tx{}
T&get(){return*this;}
};
模板
结构类型_at
{
使用类型=T1;
};
模板
结构类型_at
{
使用类型=T2;
};
模板
结构元组基础:元组叶,元组叶
{
tuple_-base(T1 a,t2b):tuple_-leaf(a),tuple_-leaf(b){}
模板
tuple_leaf get_leaf()
{
//XXX如何消除这种转换的歧义?
归还*这个;
}
};
//XXX从元组_基而非
//使tuple_base成为成员是问题的根源
模板
struct my\u tuple:tuple\u base
{
my_tuple(T1 a,t2b):tuple_base(a,b){
};
模板
typename type\u at::type&get(my\u tuple&t)
{
return(t.template get_leaf()).get();
}
模板
我的元组生成元组(T1 a,T2 b)
{
返回我的元组(a,b);
}
结构空{};
int main()
{
auto tuple=make_tuple(empty(),make_tuple(empty(),empty());
断言((std::is_empty::value));
断言(sizeof(tuple)=sizeof(empty));
获取(元组);
返回0;
}
编译器输出:

$ clang-3.5 -std=c++11 repro.cpp 
repro.cpp:47:12: error: ambiguous conversion from derived class 'tuple_base<empty, my_tuple<empty, empty> >' to base class 'tuple_leaf<0, empty, true>':
    struct tuple_base<struct empty, struct my_tuple<struct empty, struct empty> > -> tuple_leaf<0, struct empty>
    struct tuple_base<struct empty, struct my_tuple<struct empty, struct empty> > -> tuple_leaf<1, struct my_tuple<struct empty, struct empty> > -> struct my_tuple<struct empty, struct empty> -> tuple_base<struct empty, struct empty> -> tuple_leaf<0, struct empty>
    return *this;
           ^~~~~
repro.cpp:63:22: note: in instantiation of function template specialization 'tuple_base<empty, my_tuple<empty, empty> >::get_leaf<0>' requested here

  return (t.template get_leaf<i>()).get();
                     ^
repro.cpp:80:3: note: in instantiation of function template specialization 'get<0, empty, my_tuple<empty, empty> >' requested here
  get<0>(tuple);
  ^
1 error generated.
$clang-3.5-std=c++11 repo.cpp
repro.cpp:47:12:错误:从派生类“tuple\u base”到基类“tuple\u leaf”的转换不明确:
struct tuple\u base->tuple\u leaf
结构元组基础->元组叶->结构我的元组->元组基础->元组叶
归还*这个;
^~~~~
repo.cpp:63:22:注意:在函数模板专门化的实例化中,此处请求“tuple\u base::get\u leaf”
return(t.template get_leaf()).get();
^
repo.cpp:80:3:注意:在函数模板专门化的实例化中,此处请求“get”
获取(元组);
^
生成1个错误。

当你只有一把锤子时,一切看起来都像“为什么不试试CRTP”。因为CRTP解决了
template
s的所有问题

使用派生的
类D
扩展
tuple\u leaf
,并在中传递
tuple\u base的类型。(或者,编写一个
templatestruct-types{};
并将其传递进来——您所需要的只是一个唯一区分两个不同元组的类型)

修改
get_leaf
以获得适当的类,现在就没有歧义了

问题:

首先,如果没有ICF,这将使一系列相同的方法变得不同

第二,如果实现递归元组,则会出现可怕的中断。上述情况依赖于这样一个事实,即包含子元组X的元组中的类型集与子元组中的类型集不同


第三,通过上面的代码,我得到了非1大小的空结构。奇怪。如果我绕过了静态断言等,
get
segfaults。这可能是您简化问题的产物,我不确定。

好吧,当我遇到“如何使用模板解决此问题”时,一切看起来都像钉子:使用CRTP?至少在
get\u leaf
中要转换的类型中包含
tuple\u base
的类型。除非使用递归模板定义(!),否则子类型的叶子无法与父类型的叶子匹配。当我尝试这样做时,我得到的示例代码是非空元组。g++4.8和clang 3.5似乎在这些元组包含同一空类的多个实例时通过了程序。元组不能为空,因为这些实例必须有不同的地址。@casey有趣的是,它们是
is\u empty
,但大小也不为1。错误的原因是
get\u leaf
按值返回,导致
get
返回对临时值的引用。