C++ 简化构造函数重载
Posted
技术标签:
【中文标题】C++ 简化构造函数重载【英文标题】:C++ simplify constructor overloads 【发布时间】:2015-04-05 01:52:33 【问题描述】:假设我正在上课client
。我希望client
能够使用以下类型构建:
client(const boost::network::uri::uri &, const boost::network::uri::uri &)
client(const std::string &, const std::string &)
client(const char *, const char *)
但是...我也想要所有的排列...
client(const boost::network::uri::uri &, const boost::network::uri::uri &)
client(const std::string &, const std::string &)
client(const char * &, const char * &)
client(const boost::network::uri::uri &, const std::string &)
client(const std::string &, const boost::network::uri::uri &)
client(const boost::network::uri::uri &, const char * &)
client(const char * &, const boost::network::uri::uri &)
client(const std::string &, const char * &)
client(const char * &, const std::string &)
可以假设我的客户端类,为了简单起见,如下所示。
#include <string>
#include <boost/network.hpp>
#define HOST_URI "..."
#define AUTH_URI HOST_URI"..."
namespace bn = boost::network;
class client
private:
const bn::uri::uri host_;
const bn::uri::uri auth_;
public:
client(const bn::uri::uri & host = const bn::uri::uri(HOST_URI),
const bn::uri::uri & auth = const bn::uri::uri(AUTH_URI));
client(const std::string & host = const std::string(HOST_URI),
const std::string & auth = const std::string(AUTH_URI));
client(const char * & host = HOST_URI,
const char * & auth = AUTH_URI);
client(const bn::uri::uri & host = const bn::uri::uri(HOST_URI),
const std::string & auth = const std::string(AUTH_URI));
client(const std::string & host = const std::string(HOST_URI),
const bn::uri::uri & auth = const bn::uri::uri(AUTH_URI));
client(const bn::uri::uri & host = const bn::uri::uri(HOST_URI),
const char * & auth = AUTH_URI);
client(const char * & host = HOST_URI,
const bn::uri::uri & auth = const bn::uri::uri(AUTH_URI));
client(const std::string && host = const std::string(HOST_URI),
const char * & auth = AUTH_URI);
client(const char * & host = HOST_URI,
const std::string && auth = const std::string(AUTH_URI));
;
目前定义为:
#include <string>
#include <boost/network.hpp>
namespace bn = boost::network;
client::client(const bn::uri::uri & host,
const bn::uri::uri & auth)
: host_(host), auth_(auth)
...
;
client::client(const std::string & host,
const std::string & auth)
: client(bn::uri::uri(host), bn::uri::uri(auth))
client::client(const char * & host,
const char * & auth)
: client(bn::uri::uri(host), bn::uri::uri(auth))
client::client(const bn::uri::uri & host,
const std::string & auth)
: client(host, bn::uri::uri(auth))
client::client(const std::string & host,
const bn::uri::uri & auth)
: client(bn::uri::uri(host), auth)
client::client(const bn::uri::uri & host,
const char * & auth)
: client(host, bn::uri::uri(auth))
client::client(const char * & host,
const bn::uri::uri & auth)
: client(bn::uri::uri(host), auth)
client::client(const std::string & host,
const char * & auth)
: client(bn::uri::uri(host), bn::uri::uri(auth))
client::client(const char * & host,
const std::string & auth)
: client(bn::uri::uri(host), bn::uri::uri(auth))
所以我的问题是,这样做的正确和简单的方法是什么? 诚然,这次我手动完成了所有排列,但将来我可以有 3 个以上的变量来排列,这会变得很丑,很快。
【问题讨论】:
如果uri
有一个接受std::string
或char const*
的构造函数,那么你就可以使用更少的构造函数。
@RSahu 确实如此! c++ 会做某种隐式类型初始化吗?
编译器最多使用一次用户定义的转换。有关更多详细信息,请参阅en.cppreference.com/w/cpp/language/cast_operator。
您能解释一下为什么您通过非常量引用接受所有内容吗? (特别是指针版本)。你似乎没有改变论点。
如果 uri
是类名,则 client(uri & host = uri(HOST_URI),
是非法的(非 const 左值引用不能绑定到临时)
【参考方案1】:
模板怎么样:
#include <type_traits>
class client
uri host_;
uri auth_;
public:
template <typename U, typename V,
typename = typename std::enable_if<
std::is_constructible<uri, U&&>::value &&
std::is_constructible<uri, V&&>::value>::type>
client(U && u, V && v)
: host_(std::forward<U>(u))
, auth_(std::forward<V>(v))
// ...
;
【讨论】:
要使构造函数成为模板,我不需要模板类吗?仅将构造函数设为模板没有多大意义...See this post @FranciscoAguilera:你链接了一个帖子而没有真正阅读答案的前两句话,我想。 @BenVoigt 不,我确实读过它,但是,上面的代码产生了以下错误:Constructor cannot have a return type
,这让我相信它不能像我所说的那样使用构造函数来完成。跨度>
@FranciscoAguilera:我认为您可能放错了右括号。
@FranciscoAguilera:我发布的代码符合我的意思。 Demo。不过,我对其进行了编辑,以使其更加独立。【参考方案2】:
您可以创建一个可以将所有这三件事作为参数的类。你的帖子没有包含足够的细节让我写一个具体的答案,但这里是伪代码:
struct input_helper
input_helper(uri &u);
input_helper(string &u);
input_helper(char *u);
// data members to hold the inputs, maybe other processing to bring them to a common type
;
// the constructor
client(input_helper host, input_helper auth);
【讨论】:
"你可以创建一个类,它可以将所有这三个东西作为参数。" Matt,通过这样做,您不只是将创建这些重载构造函数的责任委托给此类吗? @FranciscoAguilera 是的,但是你只需要编写 3 个构造函数(这都很简单),加上主要的client
构造函数,而不是 9 个。
嗯,看起来太复杂了 xD 实际上我只需要传入 2 个 uri 对象。但它简化了我在其他任何地方的代码,以便能够将它们作为其他类型传递:string
和 const char *
,尤其是因为这样的代码不再需要包含 uri 的标头。
如果uri
有一个构造函数,它也接受const char *
和string
,那么你只需要一个接受两个uri
对象的构造函数。
你只需要向uri添加一个构造函数【参考方案3】:
由于 uri 定义了可以采用 string
和 const char *
的构造函数,因此请消除参数不包含 uri 类型的构造函数。这让 uri 的 user-defined conversion 可以为您隐式转换这些类型。
#define HOST_URI "..."
#define AUTH_URI HOST_URI"..."
class client
private:
uri host_;
uri auth_;
public:
client(const uri & host = uri(HOST_URI),
const uri & auth = uri(AUTH_URI));
client(const char * host = HOST_URI,
const char * auth = AUTH_URI);
;
-
client::client(const uri::uri & host,
const uri::uri & auth)
: host_(host), auth_(auth)
...
;
client::client(const char * host,
const char * auth)
: client(uri::uri(host), uri::uri(auth))
“我如何将它专门委托给那个构造函数?” 使用委托构造函数时要明确。
client(const char * && host, const char * && auth) :
client(uri(host), uri(auth))
或
client(const char * && host, const char * && auth) :
client(string(host), string(auth))
【讨论】:
好的,这样就回答了您之前的观察提出的一个问题:P 但是,我仍然留下原始问题。如何置换构造函数参数的所有组合,以及由于参数是右值引用类型而遇到的一些问题。 @FranciscoAguilera,我最初的建议是避免将client
构造函数使用除uri
之外的任何参数类型。这将减少您必须处理的构造函数的数量。
另外,@Rsahu、client c("", "");
给出错误:no matching constructor for initialization of client
。所以 c++ 并没有像想的那样自动为 uri 执行用户定义的转换。
@FranciscoAguilera:uri
是否有从 const char*
或仅从 std::string
的隐式转换? C++ 规则不允许在同一个参数上按顺序进行两次隐式用户定义转换。以上是关于C++ 简化构造函数重载的主要内容,如果未能解决你的问题,请参考以下文章
如果我们在 C++ 中重载构造函数,默认构造函数是不是仍然存在? [复制]
C++类与对象(详解构造函数,析构函数,拷贝构造函数,赋值重载函数)