C++17的可选和可变顺序函数参数

Optional and variably ordered function arguments with C++17

本文关键字:顺序 函数 参数 C++17      更新时间:2023-10-16

我正在努力改进串行端口类的构造函数。目前有许多重载来处理不同的场景(端口、波特率、数据位、奇偶校验、创建时打开、回调等(。为了允许这个类的用户以任意顺序只传递他/她需要的参数,我开始如下:

#include <iostream>
#include <string>
#include <tuple>
template <typename T, typename Tuple>
struct has_type;
template <typename T, typename... Us>
struct has_type<T, std::tuple<Us...>> : std::disjunction<std::is_same<T, Us>...> {};
template <typename ...UnorderedArgs>
std::string getPort(std::tuple<UnorderedArgs...> arg_set)
{
if constexpr (has_type<std::string, std::tuple<UnorderedArgs...>>::value)
return std::get<std::string &&>(std::move(arg_set));
else
return "NotSet";
}
class SerialPort
{
public:
template <typename... Args>
SerialPort(Args ...args) :
SerialPort(std::forward_as_tuple(std::move(args)...))
{}
template <typename ...UnorderedArgs>
SerialPort(std::tuple<UnorderedArgs...> arg_set) :
SerialPort(getPort(std::move(arg_set)))
{}
SerialPort(const std::string &port) // [X]
{
std::cout << "SerialPort " << port << std::endl;
}
};
int main()
{
std::string port = "/dev/tty";
SerialPort sp(1, port); // without 1 the compiler would use [X]
return 0;
}

此代码将端口设置为NotSet,因此带有if constexpr的部件无法按预期工作。如何解决这个问题?

此代码将端口设置为NotSet,因此带有if constexpr的部件无法按预期工作。如何解决这个问题?

如果引用是个问题:当你检查has_type中是否存在std::string时,std::string存在,但有引用(std::move()给出的&&,如果我没有错的话(。

解决方案:删除引用

template <typename T, typename... Us>
struct has_type<T, std::tuple<Us...>>
: std::disjunction<std::is_same<T, std::remove_reference_t<Us>>...> {};
// ..................................^^^^^^^^^^^^^^^^^^^^^^^^^^^

--编辑--

正如Jarod42所指出的(谢谢!(,这样has_type这个名称就不再正确了。

也许你需要一个has_type来检测类型的存在,同时检查引用。。。

也许最好保持原始的has_type,并使用std::remove_reference_t调用它

// ............................................VVVVVVVVVVVVVVVVVVVVVVV
if constexpr (has_type<std::string, std::tuple<std::remove_reference_t<UnorderedArgs>...>>::value)
return std::get<std::string &&>(std::move(arg_set));
else
return "NotSet";

为什么要限制自己使用C++提供的语法?这个问题需要对构建器模式和流畅的API进行修改。

使用类似的东西:

class serial_port_options
{
/* private fields to hold options */
public:
serial_port_options& set_port( int );
serial_port_options& set_baudrate( int ); 
serial_port_options& set_data_bits( int );
serial_port_options& set_parity( bool );
serial_port_options& set_open_on_creation( bool ); 
serial_port_options& set_callbacks( CALLBACK );
int get_port() const;
int get_baudrate() const;
int get_data_bits() const;
bool get_parity() const;
bool get_open_on_creation() const;
CALLBACK get_callbacks() const;
};
class SerialPort
{
public:
SerialPort(const serial_port_options&);
/* other logic and public interface */
};

使用上面的,你可以建立你的选项对象:

serial_port_options options;
options.set_port(80).set_baudrate(65536).set_data_bits(7)
.set_parity(false).set_open_on_creation(true);
SerialPort port(options);