ChatGPT解决这个技术问题 Extra ChatGPT

C++ 模板构造函数

我希望有一个没有参数的模板构造函数的非模板类。

据我了解,不可能拥有它(因为它会与默认构造函数冲突-对吗?),解决方法如下:

class A{
   template <typename U> A(U* dummy) {
   // Do something
   }
};

也许有更好的选择(或更好的解决方法)?

我会回应约翰内斯的问题。为什么?如果我们了解您要做什么,可能会有更好的技术。
@Loki如果从一系列输入中生成一些东西(比如向量的模板化迭代器构造函数),那就太好了。
@VF1 正是我来这里的原因。我的班级拥有一个枚举向量,我想用某种序列对其进行初始化。向量似乎很重,特别是 pre-brace-init(此处为 C++98)。 VAR_ARGS 看起来很糟糕(即使它可能是最好的)。传递对数组的引用似乎没问题。

J
James McNellis

调用构造函数模板时无法显式指定模板参数,因此必须通过参数推导来推导。这是因为如果你说:

Foo<int> f = Foo<int>();

<int> 是类型 Foo 的模板参数列表,而不是它的构造函数。构造函数模板的参数列表无处可去。

即使使用您的解决方法,您仍然必须传递一个参数才能调用该构造函数模板。完全不清楚您要达到的目标。


合格的构造函数调用可能是可能的,但似乎不起作用: Foo::Foo();
但是自动类型推断仍然是可能的。只要您对自动类型推断感到满意,就可以使用(非模板类的)模板构造函数。
@updogliu:当然。但是,问题是询问“没有参数的模板构造函数”如果没有函数参数,则可能不会推导出模板参数。
K
KeatsPeeks

您可以使用模板化工厂函数而不是构造函数:

class Foo
{
public:
    template <class T> static Foo* create() // could also return by value, or a smart pointer
    {
        return new Foo(...);
    }
...        
};

但是普通物体呢。
@Martin:我认为这也可以按值返回(非指针)。无论如何,RVO 应该注意消除副本。
create() 不必进行动态分配。只需return Foo(...);感谢@Samuel_xL。这对我来说是个好主意。
不幸的是,工厂方法不返回外部参照值。外部参照可以与 && 一起使用,并带有额外的 std::move .. 如果它们确实/可以..
我不明白。它如何调用带有空参数列表的模板化构造函数?它似乎称为普通的。
J
Johannes Schaub - litb

据我了解,不可能拥有它(因为它会与默认构造函数冲突 - 我是对的吗?)

你错了。它不会以任何方式发生冲突。你永远不能调用它。


1. 实际上,您可以调用模板ctor:int *p; A a(p)。 2. 偏见或理想化 ;-) 没有 John Doe。没有什么典型的德国人……用约翰内斯的话来说绝对不是。如果它们听起来没有幽默感,那只是因为 C++ 没有幽默感。
@AndreasSpindler我的意思是,如果构造函数没有参数但仍然是模板参数(仅适用于C ++ 03。C ++ 11引入了默认模板参数,这将允许调用它,当然,如果ctor 有默认参数..)。
Y
Yakk - Adam Nevraumont
template<class...>struct types{using type=types;};
template<class T>struct tag{using type=T;};
template<class Tag>using type_t=typename Tag::type;

上面的助手让你将类型作为值来工作。

class A {
  template<class T>
  A( tag<T> );
};

tag<T> 类型是一个变量,除了它所携带的类型之外没有任何状态。您可以使用它将纯类型值传递给模板函数,并由模板函数推断类型:

auto a = A(tag<int>{});

你可以传入多个类型:

class A {
  template<class T, class U, class V>
  A( types<T,U,V> );
};
auto a = A(types<int,double,std::string>{});

s
sehe

几点:

如果您声明任何构造函数(包括模板化构造函数),编译器将避免声明默认构造函数。

除非您声明一个复制构造函数(对于采用 X 或 X& 或 X const & 的 X 类),否则编译器将生成默认的复制构造函数。

如果您为接受 T const & 或 T 或 T& 的类 X 提供模板构造函数,那么编译器仍然会生成一个默认的非模板化复制构造函数,即使您可能认为它不应该,因为当 T = X 声明匹配复制构造函数声明。

在后一种情况下,您可能希望提供一个非模板复制构造函数以及模板复制构造函数。他们不会冲突。当 X 被传递时,非模板将被调用。否则模板化

高温高压


有趣的是,如果你声明类似 template X(const X&);那么它仍然不会被识别为复制构造函数,并且将创建标准的复制构造函数。
@j_kibik:是的,模板分配也是如此
...和默认的ctors。声明为 struct S { template<typename T> S() { } }; 的类声明了一个“无法访问的 ctor”。没有办法推断或通过 T。尽管如此,由于似乎存在用户定义的 ctor,因此不会生成默认 ctor。
T
Tolli

你可以这样做:

class C 
{
public:
    template <typename T> C(T*);
};
template <typename T> T* UseType() 
{
    static_cast<T*>(nullptr);
}

然后使用 int 作为构造函数的模板参数创建类型为 C 的对象:

C obj(UseType<int>());

由于您不能将模板参数传递给构造函数,因此该解决方案实质上是将模板参数转换为常规参数。在调用构造函数时使用 UseType<T>() 函数可以让查看代码的人清楚地知道,该参数的目的是告诉构造函数使用什么类型。

一个用例是构造函数创建派生类对象并将其分配给作为基类指针的成员变量。 (构造函数需要知道要使用哪个派生类,但类本身不需要模板化,因为始终使用相同的基类指针类型。)


J
Joshua Chia

这是一种解决方法。

创建 A 的模板子类 B。在 A 的构造函数中执行与模板参数无关的构造部分。在 B 的构造函数中执行与模板参数相关的部分。


u
user2616927

尝试做类似的事情

template<class T, int i> class A{

    A(){
          A(this)
    }

    A( A<int, 1>* a){
          //do something
    }
    A( A<float, 1>* a){
         //do something
    }
.
.
.
};

这也可以通过定义一个非模板类来使用模板函数来完成,这是一个从非模板默认构造函数调用的模板构造函数。
v
vrqq

只需简单地添加一个虚拟变量,例如

class A {
  template<typename T>
  A(const T&, int arg1, int arg2);
}