I'm not sure what you want to achieve, however, it looks like you want to prevent the swapping of X and Y or even automatically update the right member if it happens.
Jonathan Boccara has a nice blog post about that: https://www.fluentcpp.com/2016/12/08/strong-types-for-strong-interfaces/
The idea is that you write:
using X = NamedType<int, struct XTag>;
using Y = NamedType<int, struct YTag>;
struct Coord
{
X x;
Y y;
};
auto a = Coord{ X(4),Y(5) };
If everything is default constructable and the types in your struct are unique, you can do something with variadic templates to assign the right value to the right member.
The constructor will look a bit like:
struct Coord
{
template<typename ...T>
Coord(T &&...t)
{
assignByType(std::forward_as_tuple(x, y), std::forward<T>(t)...);
}
X x{0};
Y y{0};
};
Based on the types, you can assign the values and even assert that all types are in and that none are ignored.
An implementation of assignByType can be:
#include <utility>
#include <tuple>
template<typename ... T, typename ... U, typename V>
auto assignByTypeHelper(std::tuple<T &...> t, V &&v, U && ... u)
{
std::get<V &>(t) = std::forward<V>(v);
if constexpr( sizeof...(U))
{
assignByTypeHelper(std::move(t), std::forward<U>(u)...);
}
}
template<typename ... T, typename ... U>
auto assignByType(std::tuple<T &...> t, U && ... u)
{
static_assert(sizeof...(T) == sizeof...(U));
return assignByTypeHelper(std::move(t), std::forward<U>(u)...);
}
Full code at compiler explorer