【问题标题】:Prevent templated copy constructor from being called防止调用模板化的复制构造函数
【发布时间】:2014-09-23 19:57:30
【问题描述】:

下面将调用模板化的复制构造函数。

#include <iostream>

using namespace std;

class A
{
public:
    A(){ cout << "Class A constructor\n";}
    A(const A &a){ cout << "Class A copy constructor\n"; }
};

class B : public A
{
public:
    B(){ cout << "Class B constructor\n";}
    B(const B &a){ cout << "Class B copy constructor\n"; }
};

template <typename T>
class Template
{
public:
    Template() { cout << "Template default\n"; }
    Template(const Template &a) { cout << "Template copy constructor\n"; }

    // This gets called
    template <typename T2>
    Template(const Template<T2> &a)
    {
        cout << "Templated template copy constructor\n";
    }

};

void funcT(const Template<A> &a)
{
}

int main()
{
    Template<B> bt;

    cout << "Calling funcT(bt)\n";
    funcT(bt);

    return 0;
}

如何防止调用模板化的复制构造函数?我期待由于BA 类型,并且我通过引用传递,所以不会调用任何构造函数。我创建了一个专门的复制构造函数,希望它会被调用:

Template(const Template<A> &a)
{
    cout << "Specialized templated template copy constructor\n";
}

但这不会编译。

基本上我不想在调用funcT()时调用现有的三个构造函数。

【问题讨论】:

  • 确实做到了explicit 是你需要的like in this demo 吗?
  • Template&lt;B&gt; != Template&lt;A&gt; 老兄,这就是调用模板转换构造函数的原因。
  • 请注意:模板构造函数永远不是(!)复制构造函数
  • 好的,有道理。是为 A 创建专门的模板类的唯一选择吗?
  • @user2233706:将构造函数设为explicit,或删除模板化构造函数,改为提供explicit operator Template&lt;T2&gt;(),或在构造函数中添加enable_if 条件

标签: c++ templates


【解决方案1】:

您可以使您的函数成为接受任何Template&lt;T&gt; 但仅当 T 继承自A 的模板,这样就不会进行复制/转换:

#include <type_traits>

template <typename T>
auto funcT(const Template<T>& a)
    -> typename std::enable_if<std::is_base_of<A, T>::value>::type
{
}

DEMO


我们没有使用 C++0x

你可以自己写enable_ifis_base_of

template <bool b, typename T = void>
struct my_enable_if {};
template <typename T>
struct my_enable_if<true, T> { typedef T type; };
template <typename Base, typename Derived>
struct my_is_base_of
{
    static char test(Base*);    
    static long test(...);
    static const bool value = sizeof(test((Derived*)0)) == sizeof(char);
};

template <typename T>
typename my_enable_if<my_is_base_of<A, T>::value>::type funcT(const Template<T>& a)
{
}

C++98 DEMO

【讨论】:

  • @user2233706: enable_ifis_base_of 很容易移植到 C++98,auto 根本不需要,只是在尾部有 sfinae
  • 罗伯特的回答也有效。这个答案与罗伯特的答案相比有什么优势?
  • @user2233706:这里有额外的约束,所以这个函数只有在T 派生自A 时才起作用。我认为这是您想要的,因此您提供了 class Aclass B : public A 希望 funcT(Template&lt;A&gt;) 可以与 funcT(Template&lt;B&gt;) 一起使用
  • robert 的解决方案也适用于funcT(Template&lt;A&gt;)funcT(Template&lt;B&gt;)。不是说一种解决方案比另一种更好,而是试图看看一种解决方案比另一种解决方案有什么优势。
  • @user2233706 这一切都取决于你想要什么,我故意添加了约束希望你确实希望这个使用派生的模板参数来自A。 Robert 的解决方案甚至适用于 Template&lt;int&gt; 和几乎任何东西。
【解决方案2】:

仅仅因为 B 派生自 A 并不意味着 Template&lt;B&gt; 派生自 Template&lt;A&gt;。根据您尝试完成的模板功能可能会起作用:

template<typename T>void funcT(const Template<T> &a)
{
}

./a.out
模板默认
调用 funcT(bt)

罗伯特

【讨论】:

    猜你喜欢
    • 2011-05-24
    • 1970-01-01
    • 2021-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-12
    相关资源
    最近更新 更多