【问题标题】:Specialized constructor for template class模板类的专用构造函数
【发布时间】:2014-04-06 06:20:04
【问题描述】:

假设有 3 个类:

template <typename T>
class X;


template <typename T>
class Y;


template <typename T>
class Z;

我希望为X 定义一个构造函数,它接受Z&lt;T&gt; 类型的对象引用并返回X&lt;Y&lt;T&gt;&gt; 类型的对象。这可以通过单个模板定义实现吗?

template <typename T>
X<Y<T>>::X(Z<T>) {
  // logic to map Z<T> to Y<T> and pass it on for object creation.
}

如果我使用两个模板定义来定义构造函数,我想会有很大的副作用。

【问题讨论】:

  • 构造函数不返回任何东西。
  • 构造函数不返回任何内容,甚至 void。你想怎么用?
  • 我的意思是它应该创建一个X&lt;Y&lt;T&gt;&gt;类型的对象。另一方面,构造函数创建对象的本地副本并移交对它的引用,不是吗?如果与 new 一起使用,此对象将转移到主存储器。这就是我认为在后台发生的事情。我在哪里可以了解更多信息?
  • @n.m.我在上次编辑中为问题添加了更多详细信息。

标签: c++ templates c++11 constructor


【解决方案1】:

这样的?

template <class T>
class Z;

template <class T>
class Y;

template <class T>
class X
{
    X(Z&);
};

template<class T>
X<Y<T>> MakeX(Z<T>& z)
{
    return X<Y<T>>(z);
};

【讨论】:

  • 是的,这正是我想到的转换。为什么我必须将它命名为 MakeX?为什么不这样呢? template &lt;typename T&gt; X&lt;Y&lt;T&gt;&gt;::X(Z&lt;T&gt;)
  • @ibp73 为了获得类似的东西,您需要将整个X 模板专门化为Y&lt;T&gt;。也就是说,你必须写template &lt;typename T&gt; class X&lt;Y&lt;T&gt;&gt; { ...; X(Z&lt;T&gt;) { ... } ... }'
  • X(Z&amp;); 应该是X(Z&lt;T&gt;&amp;);
【解决方案2】:

我不确定您是否可以使用单个模板类完成您想要的工作。但是,您可以使用模板专业化来完成您正在寻找的内容。

这是此类的最小定义。

template <typename T> class X
{
};

template <typename T> class Y
{
};

template <typename T> class Z
{
};

template <typename T> class X<Y<T> >
{
   public:
      X(Z<T> z) {}
};


int main()
{
   Z<int> z;
   X<Y<int> > x(z);
}

【讨论】:

  • @R Sahu 没关系。但我不想明确定义 class X&lt;Y&lt;T&gt;&gt; 。为什么我不能添加一个简单的构造函数? template &lt;typename T&gt; X&lt;Y&lt;T&gt;&gt;::X(Z&lt;T&gt;)
  • @ibp73 你不能在X&lt;T&gt;的定义下为X&lt;Y&lt;T&gt;&gt;定义构造函数。
  • @R Sahu 这很奇怪。是否需要再次重写X&lt;Y&lt;T&gt;&gt;的定义中已经为X&lt;T&gt;定义的所有成员函数?
  • @ibp73 这将是必要的,但我明白为什么这会是一个问题。另一种选择是使用外部函数,正如 Neil Kirk 所建议的那样。
【解决方案3】:

实现这一点的直接方法:

template <typename T>
class Y{};

template <typename T>
class Z{};

template <typename T>
class X
{
    template <typename U>
    X(U){}
};

template <typename T>
template <>
X<Y<T>>::X(Z<T>){}

很遗憾,此代码不符合标准。

如果您真的不想使用辅助函数(@Neil Kirk's variant)或专门化整个类(@R Sahu's variant),您可以尝试以下变体使用std::enable_if

#include <type_traits>

template <typename T>
struct template_traits;

template
    <
        template <typename>
        class C,
        typename A
    >
struct template_traits<C<A>>
{
    using argument_type = A;
};

template
    <
        typename T,
        template <typename>
        class C
    >
struct is_instantiation_of : std::false_type{};

template
    <
        typename A,
        template <typename>
        class C
    >
struct is_instantiation_of<C<A>, C> : std::true_type{};


template <typename T>
class Y{};

template <typename T>
class Z{};

template <typename T>
class X
{
public:

    X(){}

    template
        <
            typename U = T,
            typename = typename std::enable_if<is_instantiation_of<U, Y>::value>::type
        >
    X(Z<typename template_traits<U>::argument_type>& z){}

};

使用示例:

Y<int> y_i;
Y<char> y_c;
Z<int> z_i;
Z<char> z_c;

X<int> x; // compiles
X<Y<int>> x1(z_i); // compiles
X<Y<int>> x2(z_c); // doesn't compile
X<Z<int>> x3(y_i); // doesn't compile
X<Z<int>> x4(y_c); // doesn't compile

【讨论】:

  • 我真的很喜欢您提出的第一个想法,即使存在合规性问题。我尝试了完全相同的代码,但在编译期间引发了以下错误。我也尝试使用 C++11 标准。 test_template2.cc:16:10: error: nested name specifier 'X&lt;Y&lt;T&gt; &gt;::' for declaration does not refer into a class, class template or class template partial specialization X&lt;Y&lt;T&gt;&gt;::X(Z&lt;T&gt;){}
  • @ibp73 在我的第一个代码示例中,我只是尝试制定您想要做的事情。在 C++03 和 C++11 中你都不能这样做。所以你的编译器是对的。简单的解释是,template 模板参数列表为空&lt;&gt; 的关键字不能跟在非空列表&lt;typename T&gt; 的后面。更复杂的解释是不能部分特化模板函数和模板类函数成员。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-02
  • 1970-01-01
  • 2015-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多