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::stringchar const* 的构造函数,那么你就可以使用更少的构造函数。 @RSahu 确实如此! c++ 会做某种隐式类型初始化吗? 编译器最多使用一次用户定义的转换。有关更多详细信息,请参阅en.cppreference.com/w/cpp/language/cast_operator。 您能解释一下为什么您通过非常量引用接受所有内容吗? (特别是指针版本)。你似乎没有改变论点。 如果 uri 是类名,则 client(uri &amp; 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 对象。但它简化了我在其他任何地方的代码,以便能够将它们作为其他类型传递:stringconst char *,尤其是因为这样的代码不再需要包含 uri 的标头。 如果uri 有一个构造函数,它也接受const char *string,那么你只需要一个接受两个uri 对象的构造函数。 你只需要向uri添加一个构造函数【参考方案3】:

由于 uri 定义了可以采用 stringconst 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++类-构造函数的重载

C++类-构造函数的重载

C++类与对象(详解构造函数,析构函数,拷贝构造函数,赋值重载函数)

C++类和对象(构造函数析构函数拷贝构造函数赋值运算符重载Const成员)详细解读

C++类和对象(构造函数析构函数拷贝构造函数赋值运算符重载Const成员)详细解读