I am trying to improve the constructor of a serial port class. At the moment there are many overloads to handle different scenarios (port, baudrate, data bits, parity, open on creation, callbacks etc.). To allow the user of this class to pass only the parameters he/she needs in an arbitrary order, I started as follows:
#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; } This code sets the port to NotSet, so the part with if constexpr is not working as intended. How can this be fixed?
arg_set?std::movehere is wrong.SerialPort(std::forward_as_tuple(std::move(args)...))kills it, as it turnsstd::stringintostd::string&&andstd::is_same<std::string, std::string&&>::value == falsegetPortreturn (if it were actually used) move-constructs astring. It's somewhere else?