Initialize class' template (aggregate type) member with aggregate initializer but without extra parenthesis









up vote
4
down vote

favorite
2












Having this code:



struct Vec3 
int x;
int y;
int z;
;

template <typename T>
class myProperty
public:
myProperty(const T& initValue) : m_valueinitValue
private:
T m_value;
;


When creating myProperty type object:



myProperty<int> ip1;
myProperty<Vec3> vp11, 2, 3;
// myProperty<Vec3> vp21, 2, 3; ERROR: myProperty doesn't have a matching constructor.


Is there an elegant way of making vp2 initialization work? Specializing myProperty for Vec3 is an overkill.










share|improve this question

















  • 1




    Is making myProperty itself an aggregate an option? (I.e. remove the constructor and make m_value public.) Otherwise the only solution is see is a templated constructor, that forwards its arguments to the T constructor: template <typename ...P> myProperty(P &&... p) : m_value(std::forward<P>(p)...) .
    – HolyBlackCat
    Nov 10 at 11:01










  • @HolyBlackCat, that won't compile. To make it work, you'll have to put extra parentheses, like m_value(std::forward<P>(p)...), that way vp2 case will compile but vp1 not. And making myProperty an agregate is not an option.
    – nVxx
    Nov 10 at 11:35










  • Oops. It should be : m_valuestd::forward<P>(p)..., otherwise myProperty<int> ip1; 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 at 11:38











  • @HolyBlackCat, actually no, I don't want vp1 to compile :) My bad, didn't test your suggestion thoroughly, assumed something like vp4myVec3Objet won't compile also, but it does, so this looks good :) Would accept the answer if you post it.
    – nVxx
    Nov 10 at 11:52






  • 1




    Turns out it breaks copy-construction (because it's a better match than myProperty(const myProperty &) if the parameter is non-const). I'll post an answer if I figure out how to fix that in a neat way.
    – HolyBlackCat
    Nov 10 at 12:07














up vote
4
down vote

favorite
2












Having this code:



struct Vec3 
int x;
int y;
int z;
;

template <typename T>
class myProperty
public:
myProperty(const T& initValue) : m_valueinitValue
private:
T m_value;
;


When creating myProperty type object:



myProperty<int> ip1;
myProperty<Vec3> vp11, 2, 3;
// myProperty<Vec3> vp21, 2, 3; ERROR: myProperty doesn't have a matching constructor.


Is there an elegant way of making vp2 initialization work? Specializing myProperty for Vec3 is an overkill.










share|improve this question

















  • 1




    Is making myProperty itself an aggregate an option? (I.e. remove the constructor and make m_value public.) Otherwise the only solution is see is a templated constructor, that forwards its arguments to the T constructor: template <typename ...P> myProperty(P &&... p) : m_value(std::forward<P>(p)...) .
    – HolyBlackCat
    Nov 10 at 11:01










  • @HolyBlackCat, that won't compile. To make it work, you'll have to put extra parentheses, like m_value(std::forward<P>(p)...), that way vp2 case will compile but vp1 not. And making myProperty an agregate is not an option.
    – nVxx
    Nov 10 at 11:35










  • Oops. It should be : m_valuestd::forward<P>(p)..., otherwise myProperty<int> ip1; 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 at 11:38











  • @HolyBlackCat, actually no, I don't want vp1 to compile :) My bad, didn't test your suggestion thoroughly, assumed something like vp4myVec3Objet won't compile also, but it does, so this looks good :) Would accept the answer if you post it.
    – nVxx
    Nov 10 at 11:52






  • 1




    Turns out it breaks copy-construction (because it's a better match than myProperty(const myProperty &) if the parameter is non-const). I'll post an answer if I figure out how to fix that in a neat way.
    – HolyBlackCat
    Nov 10 at 12:07












up vote
4
down vote

favorite
2









up vote
4
down vote

favorite
2






2





Having this code:



struct Vec3 
int x;
int y;
int z;
;

template <typename T>
class myProperty
public:
myProperty(const T& initValue) : m_valueinitValue
private:
T m_value;
;


When creating myProperty type object:



myProperty<int> ip1;
myProperty<Vec3> vp11, 2, 3;
// myProperty<Vec3> vp21, 2, 3; ERROR: myProperty doesn't have a matching constructor.


Is there an elegant way of making vp2 initialization work? Specializing myProperty for Vec3 is an overkill.










share|improve this question













Having this code:



struct Vec3 
int x;
int y;
int z;
;

template <typename T>
class myProperty
public:
myProperty(const T& initValue) : m_valueinitValue
private:
T m_value;
;


When creating myProperty type object:



myProperty<int> ip1;
myProperty<Vec3> vp11, 2, 3;
// myProperty<Vec3> vp21, 2, 3; ERROR: myProperty doesn't have a matching constructor.


Is there an elegant way of making vp2 initialization work? Specializing myProperty for Vec3 is an overkill.







c++ class templates constructor c++14






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 10 at 10:55









nVxx

244212




244212







  • 1




    Is making myProperty itself an aggregate an option? (I.e. remove the constructor and make m_value public.) Otherwise the only solution is see is a templated constructor, that forwards its arguments to the T constructor: template <typename ...P> myProperty(P &&... p) : m_value(std::forward<P>(p)...) .
    – HolyBlackCat
    Nov 10 at 11:01










  • @HolyBlackCat, that won't compile. To make it work, you'll have to put extra parentheses, like m_value(std::forward<P>(p)...), that way vp2 case will compile but vp1 not. And making myProperty an agregate is not an option.
    – nVxx
    Nov 10 at 11:35










  • Oops. It should be : m_valuestd::forward<P>(p)..., otherwise myProperty<int> ip1; 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 at 11:38











  • @HolyBlackCat, actually no, I don't want vp1 to compile :) My bad, didn't test your suggestion thoroughly, assumed something like vp4myVec3Objet won't compile also, but it does, so this looks good :) Would accept the answer if you post it.
    – nVxx
    Nov 10 at 11:52






  • 1




    Turns out it breaks copy-construction (because it's a better match than myProperty(const myProperty &) if the parameter is non-const). I'll post an answer if I figure out how to fix that in a neat way.
    – HolyBlackCat
    Nov 10 at 12:07












  • 1




    Is making myProperty itself an aggregate an option? (I.e. remove the constructor and make m_value public.) Otherwise the only solution is see is a templated constructor, that forwards its arguments to the T constructor: template <typename ...P> myProperty(P &&... p) : m_value(std::forward<P>(p)...) .
    – HolyBlackCat
    Nov 10 at 11:01










  • @HolyBlackCat, that won't compile. To make it work, you'll have to put extra parentheses, like m_value(std::forward<P>(p)...), that way vp2 case will compile but vp1 not. And making myProperty an agregate is not an option.
    – nVxx
    Nov 10 at 11:35










  • Oops. It should be : m_valuestd::forward<P>(p)..., otherwise myProperty<int> ip1; 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 at 11:38











  • @HolyBlackCat, actually no, I don't want vp1 to compile :) My bad, didn't test your suggestion thoroughly, assumed something like vp4myVec3Objet won't compile also, but it does, so this looks good :) Would accept the answer if you post it.
    – nVxx
    Nov 10 at 11:52






  • 1




    Turns out it breaks copy-construction (because it's a better match than myProperty(const myProperty &) if the parameter is non-const). I'll post an answer if I figure out how to fix that in a neat way.
    – HolyBlackCat
    Nov 10 at 12:07







1




1




Is making myProperty itself an aggregate an option? (I.e. remove the constructor and make m_value public.) Otherwise the only solution is see is a templated constructor, that forwards its arguments to the T constructor: template <typename ...P> myProperty(P &&... p) : m_value(std::forward<P>(p)...) .
– HolyBlackCat
Nov 10 at 11:01




Is making myProperty itself an aggregate an option? (I.e. remove the constructor and make m_value public.) Otherwise the only solution is see is a templated constructor, that forwards its arguments to the T constructor: template <typename ...P> myProperty(P &&... p) : m_value(std::forward<P>(p)...) .
– HolyBlackCat
Nov 10 at 11:01












@HolyBlackCat, that won't compile. To make it work, you'll have to put extra parentheses, like m_value(std::forward<P>(p)...), that way vp2 case will compile but vp1 not. And making myProperty an agregate is not an option.
– nVxx
Nov 10 at 11:35




@HolyBlackCat, that won't compile. To make it work, you'll have to put extra parentheses, like m_value(std::forward<P>(p)...), that way vp2 case will compile but vp1 not. And making myProperty an agregate is not an option.
– nVxx
Nov 10 at 11:35












Oops. It should be : m_valuestd::forward<P>(p)..., otherwise myProperty<int> ip1; 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 at 11:38





Oops. It should be : m_valuestd::forward<P>(p)..., otherwise myProperty<int> ip1; 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 at 11:38













@HolyBlackCat, actually no, I don't want vp1 to compile :) My bad, didn't test your suggestion thoroughly, assumed something like vp4myVec3Objet won't compile also, but it does, so this looks good :) Would accept the answer if you post it.
– nVxx
Nov 10 at 11:52




@HolyBlackCat, actually no, I don't want vp1 to compile :) My bad, didn't test your suggestion thoroughly, assumed something like vp4myVec3Objet won't compile also, but it does, so this looks good :) Would accept the answer if you post it.
– nVxx
Nov 10 at 11:52




1




1




Turns out it breaks copy-construction (because it's a better match than myProperty(const myProperty &) if the parameter is non-const). I'll post an answer if I figure out how to fix that in a neat way.
– HolyBlackCat
Nov 10 at 12:07




Turns out it breaks copy-construction (because it's a better match than myProperty(const myProperty &) if the parameter is non-const). I'll post an answer if I figure out how to fix that in a neat way.
– HolyBlackCat
Nov 10 at 12:07












1 Answer
1






active

oldest

votes

















up vote
6
down vote













A simple solution is to use a variadic template constructor:



template <typename ...P> myProperty(P &&... p) : m_valuestd::forward<P>(p)... 


It makes myProperty<Vec3> vp21, 2, 3; compile.



Also it stops myProperty<Vec3> vp11, 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(Tstd::declval<P>()...);

// ...

template
<
typename ...P,
typename = std::enable_if_t<std::experimental::is_detected_v<list_constructible, T, P...>>
>
myProperty(P &&... p) : m_valuestd::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(Tstd::declval<P>()...);

// ...

template
<
typename ...P,
typename = std::enable_if_t<is_detected<void, list_constructible, T, P...>::value>
>
myProperty(P &&... p) : m_valuestd::forward<P>(p)...





share|improve this answer






















  • Yet only an upvote, to have some time to experiment with this solution and also keep the question open for alternative solutions.
    – nVxx
    yesterday










Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53238233%2finitialize-class-template-aggregate-type-member-with-aggregate-initializer-bu%23new-answer', 'question_page');

);

Post as a guest






























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
6
down vote













A simple solution is to use a variadic template constructor:



template <typename ...P> myProperty(P &&... p) : m_valuestd::forward<P>(p)... 


It makes myProperty<Vec3> vp21, 2, 3; compile.



Also it stops myProperty<Vec3> vp11, 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(Tstd::declval<P>()...);

// ...

template
<
typename ...P,
typename = std::enable_if_t<std::experimental::is_detected_v<list_constructible, T, P...>>
>
myProperty(P &&... p) : m_valuestd::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(Tstd::declval<P>()...);

// ...

template
<
typename ...P,
typename = std::enable_if_t<is_detected<void, list_constructible, T, P...>::value>
>
myProperty(P &&... p) : m_valuestd::forward<P>(p)...





share|improve this answer






















  • Yet only an upvote, to have some time to experiment with this solution and also keep the question open for alternative solutions.
    – nVxx
    yesterday














up vote
6
down vote













A simple solution is to use a variadic template constructor:



template <typename ...P> myProperty(P &&... p) : m_valuestd::forward<P>(p)... 


It makes myProperty<Vec3> vp21, 2, 3; compile.



Also it stops myProperty<Vec3> vp11, 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(Tstd::declval<P>()...);

// ...

template
<
typename ...P,
typename = std::enable_if_t<std::experimental::is_detected_v<list_constructible, T, P...>>
>
myProperty(P &&... p) : m_valuestd::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(Tstd::declval<P>()...);

// ...

template
<
typename ...P,
typename = std::enable_if_t<is_detected<void, list_constructible, T, P...>::value>
>
myProperty(P &&... p) : m_valuestd::forward<P>(p)...





share|improve this answer






















  • Yet only an upvote, to have some time to experiment with this solution and also keep the question open for alternative solutions.
    – nVxx
    yesterday












up vote
6
down vote










up vote
6
down vote









A simple solution is to use a variadic template constructor:



template <typename ...P> myProperty(P &&... p) : m_valuestd::forward<P>(p)... 


It makes myProperty<Vec3> vp21, 2, 3; compile.



Also it stops myProperty<Vec3> vp11, 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(Tstd::declval<P>()...);

// ...

template
<
typename ...P,
typename = std::enable_if_t<std::experimental::is_detected_v<list_constructible, T, P...>>
>
myProperty(P &&... p) : m_valuestd::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(Tstd::declval<P>()...);

// ...

template
<
typename ...P,
typename = std::enable_if_t<is_detected<void, list_constructible, T, P...>::value>
>
myProperty(P &&... p) : m_valuestd::forward<P>(p)...





share|improve this answer














A simple solution is to use a variadic template constructor:



template <typename ...P> myProperty(P &&... p) : m_valuestd::forward<P>(p)... 


It makes myProperty<Vec3> vp21, 2, 3; compile.



Also it stops myProperty<Vec3> vp11, 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(Tstd::declval<P>()...);

// ...

template
<
typename ...P,
typename = std::enable_if_t<std::experimental::is_detected_v<list_constructible, T, P...>>
>
myProperty(P &&... p) : m_valuestd::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(Tstd::declval<P>()...);

// ...

template
<
typename ...P,
typename = std::enable_if_t<is_detected<void, list_constructible, T, P...>::value>
>
myProperty(P &&... p) : m_valuestd::forward<P>(p)...






share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 10 at 12:37

























answered Nov 10 at 12:30









HolyBlackCat

14.6k23361




14.6k23361











  • Yet only an upvote, to have some time to experiment with this solution and also keep the question open for alternative solutions.
    – nVxx
    yesterday
















  • Yet only an upvote, to have some time to experiment with this solution and also keep the question open for alternative solutions.
    – nVxx
    yesterday















Yet only an upvote, to have some time to experiment with this solution and also keep the question open for alternative solutions.
– nVxx
yesterday




Yet only an upvote, to have some time to experiment with this solution and also keep the question open for alternative solutions.
– nVxx
yesterday

















 

draft saved


draft discarded















































 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53238233%2finitialize-class-template-aggregate-type-member-with-aggregate-initializer-bu%23new-answer', 'question_page');

);

Post as a guest














































































這個網誌中的熱門文章

How to read a connectionString WITH PROVIDER in .NET Core?

Node.js Script on GitHub Pages or Amazon S3

Museum of Modern and Contemporary Art of Trento and Rovereto