A simple solution is to use a variadic template constructor:
template <typename ...P> myProperty(P &&... p) : m_value{std::forward<P>(p)...} {}
It makes myProperty<Vec3> vp2{1, 2, 3};
compile.
Also it stops myProperty<Vec3> vp1{{1, 2, 3}};
from compiling (which seems to match your intentions).
The problem with this option is that it prevents copy construction from working propertly.
(If the parameter is a non-const myProperty<T>
lvalue, then this variadic constructor is a better match than myProperty(const myProperty &)
.)
This can be solved with SFINAE:
C++17 with <experimental/type_traits>
:
#include <experimental/type_traits>
#include <utility>
template <typename T, typename ...P> using list_constructible = decltype(T{std::declval<P>()...});
// ...
template
<
typename ...P,
typename = std::enable_if_t<std::experimental::is_detected_v<list_constructible, T, P...>>
>
myProperty(P &&... p) : m_value{std::forward<P>(p)...} {}
C++14:
#include <type_traits>
#include <utility>
template <typename...> using void_t = void;
template <typename DummyVoid, template <typename...> class A, typename ...B> struct is_detected : std::false_type {};
template <template <typename...> class A, typename ...B> struct is_detected<void_t<A<B...>>, A, B...> : std::true_type {};
template <typename T, typename ...P> using list_constructible = decltype(T{std::declval<P>()...});
// ...
template
<
typename ...P,
typename = std::enable_if_t<is_detected<void, list_constructible, T, P...>::value>
>
myProperty(P &&... p) : m_value{std::forward<P>(p)...} {}
(p)...) {}`.
(p)...})`, that way `vp2` case will compile but `vp1` not. And making `myProperty` an agregate is not an option.
– nVxx Nov 10 '18 at 11:35(p)...}`, otherwise `myProperty ip{1};` doesn't compile. *"vp2 case will compile but vp1 not"* Does it mean you want both `vp1` and `vp2` to compile, not only `vp2`?
– HolyBlackCat Nov 10 '18 at 11:38