I met a wired problem that my user-defined-constructor can only work on a non-array std::variant.
Here is the code:
template<size_t N>
struct StringLiteral
{
constexpr StringLiteral(const char (&str)[N]) { std::copy_n(str, N, value); }
char value[N];
};
template<StringLiteral _name, typename... ArgTys>
struct Message
{
static_assert(sizeof(_name.value) <= 11U, "Name of message must less than 11 characters.");
using MsgArg = std::variant<ArgTys...>;
static constexpr auto NAME = _name.value;
static constexpr auto SIZE = (sizeof(ArgTys) + ...);
static constexpr auto COUNT = sizeof...(ArgTys);
static void Register(void)
{
cout << "size of the message \"" << NAME << "\" is " << SIZE << '.' << endl;
}
static void Cast(int iDest, const Vector& vecOrigin, void* pClient, ArgTys... args)
{
auto f = [](auto&& arg)
{
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, int>)
std::cout << "int sent: " << arg << '\n';
else if constexpr (std::is_same_v<T, float>)
std::cout << "float sent: " << arg << '\n';
else if constexpr (std::is_same_v<T, const char*>)
std::cout << "string sent: " << std::quoted(arg) << '\n';
else if constexpr (std::is_same_v<T, Vector>)
cout << "vector sent: " << endl << arg;
else if constexpr (std::is_same_v<T, short>)
std::cout << "short sent: " << arg << '\n';
else if constexpr (std::is_same_v<T, unsigned char>)
std::cout << "byte sent: " << arg << '\n';
else
static_assert(always_false_v<T>, "Unknow type was sent!");
};
cout << "Cast message to " << iDest << " at " << endl << vecOrigin << " for " << pClient << endl;
std::array<MsgArg, COUNT> rgArgs = { args... };
for (auto& arg : rgArgs)
{
std::visit(f, arg);
}
}
};
int main()
{
using gmsgGiveWpn = Message<"GiveWpn", unsigned char, Vector, const char *, short>;
std::array<gmsgGiveWpn::MsgArg, 2> v = { Vector(1, 1, 1), 0U };
return EXIT_SUCCESS;
}
With the custom class type 'class Vector' has constructor:
constexpr Vector(Vector&& s) = default;
Vector& operator=(const Vector& s) = default;
Vector& operator=(Vector&& s) = default;
constexpr Vector() : x(0), y(0), z(0) {}
constexpr Vector(Arithmetic auto X, Arithmetic auto Y, Arithmetic auto Z) : x(static_cast<vec_t>(X)), y(static_cast<vec_t>(Y)), z(static_cast<vec_t>(Z)) {}
constexpr Vector(const Vector2D& v2d, Arithmetic auto Z) : x(v2d.x), y(v2d.y), z(static_cast<vec_t>(Z)) {}
template<Arithmetic T, std::size_t size> requires(size >= 3U) explicit constexpr Vector(const T(&rgfl)[size]) : x(static_cast<vec_t>(rgfl[0])), y(static_cast<vec_t>(rgfl[1])), z(static_cast<vec_t>(rgfl[2])) {}
Compile with VS2022/C++20, MSVC gave me the following error exact on the line where I put my packed arguments in the initializer brackets:
error C2440: 'initializing': cannot convert from 'Vector' to '_Ty'
with
[
_Ty=std::variant<unsigned char,Vector,const char *,short>
]
message : No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
However, when I tried
gmsgGiveWpn::MsgArg v = Vector(0, 0, 0);
It just works as all I intended.
What should I do to define a proper constructor to make my Vector works in initializer-list?
Edit:
Tested on default array, i.e. MsgArg rg[] = {Vector(), 2};, does not work.
Tested adding an extra layer of {} surrounding the initializer list, i.e. std::array<MsgArg, COUNT> rgArgs = { {args}... };, does not work.