Limit allowed COM Interfaces by using template function with limited variadic parameters (std::is_same)
I have wrapper classes contaning COM pointers (or smart pointers) to different interfaces.
INTEND:
Some COM classes can be obtained from various other COM interfaces, and I want to make a template constructor with variadic types, which would allow passing arguments only of appropriate types.
something like:
template <class T, class = typename
std::enable_if<std::is_base_of<IUnknown, T>::value>::type, class ... Types>
class WithCOMptrbase
...>::type> /*there needs to be a proper version*/
WithCOMptrbase(TypeOther* ptr)
: ptr_(cQueryInterface<T>(ptr))
//other methods
;
helper function:
template <class U, class = typename
std::enable_if<std::is_base_of<IUnknown, U>::value>::type>
T* cQueryInterface<T>(U *ptr)
T* out;
HRESULT hr = ptr->QueryInterface(__uuidof(T), (void**)&out);
if (!SUCCEEED(hr)) throw _com_error(hr);
return out;
Therefore, I will define my wrapper class
class WrapperClass : protected WithCOMptrbase<IThis, IInterface1, IInterface2, IInterface3>
//methods
;
So far I have found this thread:
How to make a variadic is_same?
but it is only about structs, not functions.
My goal is to limit the possibility of passing inapproprtiate Interface pointer, hence not to deal with wrong interface errors at runtime.
UPDATE:
Since Composition is preferable over inheritance, I've done some rethinking and decided to use a template function rather than a template class. So far I've managed to combine given answers and came up with this:
template <bool S, class Out, class Other, typename
std::enable_if<S>::type* = nullptr>
//copy-construct Smart Pointer for same Interfaces
WComPtr<Out> WFilterSame(const WComPtr<Other>& pOther)
return WComPtr<Out>(pOther);
template <bool S, class Out, class Other, typename
std::enable_if<!S>::type* = nullptr>
//Query Interface if differ
WComPtr<Out> WFilterSame(const WComPtr<Other>& pOther)
return pOther.QueryInterface<Out>();
template <class Out, class ... Permitted, class Other>
WComPtr<Out> WFilterComInterfPtr(const WComPtr<Other>& pOther)
(std::is_same<Permitted, Other>::value
Now I can define a constructor of my COM wrapper class:
class WComClass
private:
WComPtr<Interface> pComPtr_; //My Smart COM pointer
template <class Other>
WComPtr<Interface> WFilter(const WComPtr<Other>& pOther)
return WFilterComInterfPtr<Interface, IAllowed1, IAllowed2>(pOther);
public:
template <class Other>
WComClass(const WComPtr<Other>& pOther)
: pComPtr_(WFilter(pOther))
//methods
;
So far it behaved as intended (WFilterComInterfPtr), I don't expect it to fail in the wrapper class costructor.
com c++17 variadic-templates sfinae fold-expression
|
show 2 more comments
I have wrapper classes contaning COM pointers (or smart pointers) to different interfaces.
INTEND:
Some COM classes can be obtained from various other COM interfaces, and I want to make a template constructor with variadic types, which would allow passing arguments only of appropriate types.
something like:
template <class T, class = typename
std::enable_if<std::is_base_of<IUnknown, T>::value>::type, class ... Types>
class WithCOMptrbase
...>::type> /*there needs to be a proper version*/
WithCOMptrbase(TypeOther* ptr)
: ptr_(cQueryInterface<T>(ptr))
//other methods
;
helper function:
template <class U, class = typename
std::enable_if<std::is_base_of<IUnknown, U>::value>::type>
T* cQueryInterface<T>(U *ptr)
T* out;
HRESULT hr = ptr->QueryInterface(__uuidof(T), (void**)&out);
if (!SUCCEEED(hr)) throw _com_error(hr);
return out;
Therefore, I will define my wrapper class
class WrapperClass : protected WithCOMptrbase<IThis, IInterface1, IInterface2, IInterface3>
//methods
;
So far I have found this thread:
How to make a variadic is_same?
but it is only about structs, not functions.
My goal is to limit the possibility of passing inapproprtiate Interface pointer, hence not to deal with wrong interface errors at runtime.
UPDATE:
Since Composition is preferable over inheritance, I've done some rethinking and decided to use a template function rather than a template class. So far I've managed to combine given answers and came up with this:
template <bool S, class Out, class Other, typename
std::enable_if<S>::type* = nullptr>
//copy-construct Smart Pointer for same Interfaces
WComPtr<Out> WFilterSame(const WComPtr<Other>& pOther)
return WComPtr<Out>(pOther);
template <bool S, class Out, class Other, typename
std::enable_if<!S>::type* = nullptr>
//Query Interface if differ
WComPtr<Out> WFilterSame(const WComPtr<Other>& pOther)
return pOther.QueryInterface<Out>();
template <class Out, class ... Permitted, class Other>
WComPtr<Out> WFilterComInterfPtr(const WComPtr<Other>& pOther)
(std::is_same<Permitted, Other>::value
Now I can define a constructor of my COM wrapper class:
class WComClass
private:
WComPtr<Interface> pComPtr_; //My Smart COM pointer
template <class Other>
WComPtr<Interface> WFilter(const WComPtr<Other>& pOther)
return WFilterComInterfPtr<Interface, IAllowed1, IAllowed2>(pOther);
public:
template <class Other>
WComClass(const WComPtr<Other>& pOther)
: pComPtr_(WFilter(pOther))
//methods
;
So far it behaved as intended (WFilterComInterfPtr), I don't expect it to fail in the wrapper class costructor.
com c++17 variadic-templates sfinae fold-expression
Unless you restrict what version of C++, we'll assume c++17 at this point. Especially because it makes it easier to solve. :)
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:23
Second, what goes wrong with your solution? A syntax error inWithCOMptrbase
?
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:25
Do you want the stored TypeOther to support all of the interfaces, or one of the interfaces? One seems strange. Ah, you want only poitners ofT
or` Types...` to be permited, and then you want to always store it as aT
? Sort of like a variant but no way to go back to the type stored.
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:29
@Yakk-AdamNevraumont I want to support All of the provided interfaces.
– Sergey Kolesnik
Nov 15 '18 at 18:35
2
@Yakk-AdamNevraumont, the Idea is to allow passing only the provided Interfaces, so in my case I would be able to construct WithCOMptrbase only when "IThis, IInterface1, IInterface2, IInterface3" types are passed as arguments. For now I successfully compile with those allowed tyes and get compile error for other (not allowed) interfaces.
– Sergey Kolesnik
Nov 15 '18 at 19:01
|
show 2 more comments
I have wrapper classes contaning COM pointers (or smart pointers) to different interfaces.
INTEND:
Some COM classes can be obtained from various other COM interfaces, and I want to make a template constructor with variadic types, which would allow passing arguments only of appropriate types.
something like:
template <class T, class = typename
std::enable_if<std::is_base_of<IUnknown, T>::value>::type, class ... Types>
class WithCOMptrbase
...>::type> /*there needs to be a proper version*/
WithCOMptrbase(TypeOther* ptr)
: ptr_(cQueryInterface<T>(ptr))
//other methods
;
helper function:
template <class U, class = typename
std::enable_if<std::is_base_of<IUnknown, U>::value>::type>
T* cQueryInterface<T>(U *ptr)
T* out;
HRESULT hr = ptr->QueryInterface(__uuidof(T), (void**)&out);
if (!SUCCEEED(hr)) throw _com_error(hr);
return out;
Therefore, I will define my wrapper class
class WrapperClass : protected WithCOMptrbase<IThis, IInterface1, IInterface2, IInterface3>
//methods
;
So far I have found this thread:
How to make a variadic is_same?
but it is only about structs, not functions.
My goal is to limit the possibility of passing inapproprtiate Interface pointer, hence not to deal with wrong interface errors at runtime.
UPDATE:
Since Composition is preferable over inheritance, I've done some rethinking and decided to use a template function rather than a template class. So far I've managed to combine given answers and came up with this:
template <bool S, class Out, class Other, typename
std::enable_if<S>::type* = nullptr>
//copy-construct Smart Pointer for same Interfaces
WComPtr<Out> WFilterSame(const WComPtr<Other>& pOther)
return WComPtr<Out>(pOther);
template <bool S, class Out, class Other, typename
std::enable_if<!S>::type* = nullptr>
//Query Interface if differ
WComPtr<Out> WFilterSame(const WComPtr<Other>& pOther)
return pOther.QueryInterface<Out>();
template <class Out, class ... Permitted, class Other>
WComPtr<Out> WFilterComInterfPtr(const WComPtr<Other>& pOther)
(std::is_same<Permitted, Other>::value
Now I can define a constructor of my COM wrapper class:
class WComClass
private:
WComPtr<Interface> pComPtr_; //My Smart COM pointer
template <class Other>
WComPtr<Interface> WFilter(const WComPtr<Other>& pOther)
return WFilterComInterfPtr<Interface, IAllowed1, IAllowed2>(pOther);
public:
template <class Other>
WComClass(const WComPtr<Other>& pOther)
: pComPtr_(WFilter(pOther))
//methods
;
So far it behaved as intended (WFilterComInterfPtr), I don't expect it to fail in the wrapper class costructor.
com c++17 variadic-templates sfinae fold-expression
I have wrapper classes contaning COM pointers (or smart pointers) to different interfaces.
INTEND:
Some COM classes can be obtained from various other COM interfaces, and I want to make a template constructor with variadic types, which would allow passing arguments only of appropriate types.
something like:
template <class T, class = typename
std::enable_if<std::is_base_of<IUnknown, T>::value>::type, class ... Types>
class WithCOMptrbase
...>::type> /*there needs to be a proper version*/
WithCOMptrbase(TypeOther* ptr)
: ptr_(cQueryInterface<T>(ptr))
//other methods
;
helper function:
template <class U, class = typename
std::enable_if<std::is_base_of<IUnknown, U>::value>::type>
T* cQueryInterface<T>(U *ptr)
T* out;
HRESULT hr = ptr->QueryInterface(__uuidof(T), (void**)&out);
if (!SUCCEEED(hr)) throw _com_error(hr);
return out;
Therefore, I will define my wrapper class
class WrapperClass : protected WithCOMptrbase<IThis, IInterface1, IInterface2, IInterface3>
//methods
;
So far I have found this thread:
How to make a variadic is_same?
but it is only about structs, not functions.
My goal is to limit the possibility of passing inapproprtiate Interface pointer, hence not to deal with wrong interface errors at runtime.
UPDATE:
Since Composition is preferable over inheritance, I've done some rethinking and decided to use a template function rather than a template class. So far I've managed to combine given answers and came up with this:
template <bool S, class Out, class Other, typename
std::enable_if<S>::type* = nullptr>
//copy-construct Smart Pointer for same Interfaces
WComPtr<Out> WFilterSame(const WComPtr<Other>& pOther)
return WComPtr<Out>(pOther);
template <bool S, class Out, class Other, typename
std::enable_if<!S>::type* = nullptr>
//Query Interface if differ
WComPtr<Out> WFilterSame(const WComPtr<Other>& pOther)
return pOther.QueryInterface<Out>();
template <class Out, class ... Permitted, class Other>
WComPtr<Out> WFilterComInterfPtr(const WComPtr<Other>& pOther)
(std::is_same<Permitted, Other>::value
Now I can define a constructor of my COM wrapper class:
class WComClass
private:
WComPtr<Interface> pComPtr_; //My Smart COM pointer
template <class Other>
WComPtr<Interface> WFilter(const WComPtr<Other>& pOther)
return WFilterComInterfPtr<Interface, IAllowed1, IAllowed2>(pOther);
public:
template <class Other>
WComClass(const WComPtr<Other>& pOther)
: pComPtr_(WFilter(pOther))
//methods
;
So far it behaved as intended (WFilterComInterfPtr), I don't expect it to fail in the wrapper class costructor.
com c++17 variadic-templates sfinae fold-expression
com c++17 variadic-templates sfinae fold-expression
edited Jan 28 at 13:56
max66
38.4k74473
38.4k74473
asked Nov 15 '18 at 18:21
Sergey KolesnikSergey Kolesnik
697
697
Unless you restrict what version of C++, we'll assume c++17 at this point. Especially because it makes it easier to solve. :)
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:23
Second, what goes wrong with your solution? A syntax error inWithCOMptrbase
?
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:25
Do you want the stored TypeOther to support all of the interfaces, or one of the interfaces? One seems strange. Ah, you want only poitners ofT
or` Types...` to be permited, and then you want to always store it as aT
? Sort of like a variant but no way to go back to the type stored.
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:29
@Yakk-AdamNevraumont I want to support All of the provided interfaces.
– Sergey Kolesnik
Nov 15 '18 at 18:35
2
@Yakk-AdamNevraumont, the Idea is to allow passing only the provided Interfaces, so in my case I would be able to construct WithCOMptrbase only when "IThis, IInterface1, IInterface2, IInterface3" types are passed as arguments. For now I successfully compile with those allowed tyes and get compile error for other (not allowed) interfaces.
– Sergey Kolesnik
Nov 15 '18 at 19:01
|
show 2 more comments
Unless you restrict what version of C++, we'll assume c++17 at this point. Especially because it makes it easier to solve. :)
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:23
Second, what goes wrong with your solution? A syntax error inWithCOMptrbase
?
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:25
Do you want the stored TypeOther to support all of the interfaces, or one of the interfaces? One seems strange. Ah, you want only poitners ofT
or` Types...` to be permited, and then you want to always store it as aT
? Sort of like a variant but no way to go back to the type stored.
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:29
@Yakk-AdamNevraumont I want to support All of the provided interfaces.
– Sergey Kolesnik
Nov 15 '18 at 18:35
2
@Yakk-AdamNevraumont, the Idea is to allow passing only the provided Interfaces, so in my case I would be able to construct WithCOMptrbase only when "IThis, IInterface1, IInterface2, IInterface3" types are passed as arguments. For now I successfully compile with those allowed tyes and get compile error for other (not allowed) interfaces.
– Sergey Kolesnik
Nov 15 '18 at 19:01
Unless you restrict what version of C++, we'll assume c++17 at this point. Especially because it makes it easier to solve. :)
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:23
Unless you restrict what version of C++, we'll assume c++17 at this point. Especially because it makes it easier to solve. :)
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:23
Second, what goes wrong with your solution? A syntax error in
WithCOMptrbase
?– Yakk - Adam Nevraumont
Nov 15 '18 at 18:25
Second, what goes wrong with your solution? A syntax error in
WithCOMptrbase
?– Yakk - Adam Nevraumont
Nov 15 '18 at 18:25
Do you want the stored TypeOther to support all of the interfaces, or one of the interfaces? One seems strange. Ah, you want only poitners of
T
or` Types...` to be permited, and then you want to always store it as a T
? Sort of like a variant but no way to go back to the type stored.– Yakk - Adam Nevraumont
Nov 15 '18 at 18:29
Do you want the stored TypeOther to support all of the interfaces, or one of the interfaces? One seems strange. Ah, you want only poitners of
T
or` Types...` to be permited, and then you want to always store it as a T
? Sort of like a variant but no way to go back to the type stored.– Yakk - Adam Nevraumont
Nov 15 '18 at 18:29
@Yakk-AdamNevraumont I want to support All of the provided interfaces.
– Sergey Kolesnik
Nov 15 '18 at 18:35
@Yakk-AdamNevraumont I want to support All of the provided interfaces.
– Sergey Kolesnik
Nov 15 '18 at 18:35
2
2
@Yakk-AdamNevraumont, the Idea is to allow passing only the provided Interfaces, so in my case I would be able to construct WithCOMptrbase only when "IThis, IInterface1, IInterface2, IInterface3" types are passed as arguments. For now I successfully compile with those allowed tyes and get compile error for other (not allowed) interfaces.
– Sergey Kolesnik
Nov 15 '18 at 19:01
@Yakk-AdamNevraumont, the Idea is to allow passing only the provided Interfaces, so in my case I would be able to construct WithCOMptrbase only when "IThis, IInterface1, IInterface2, IInterface3" types are passed as arguments. For now I successfully compile with those allowed tyes and get compile error for other (not allowed) interfaces.
– Sergey Kolesnik
Nov 15 '18 at 19:01
|
show 2 more comments
2 Answers
2
active
oldest
votes
Try with
template <class TypeOther, class =
std::enable_if_t<(std::is_same_v<Types, TypeOther> || ...)>>
WithCOMptrbase(TypeOther* ptr)
: ptr_(cQueryInterface<T>(ptr))
I mean... you're using three ellipsis instead of one (remove the ellipsis after ::value
and the one after Types
) and you need an additional couple of parentheses.
Off topic: are you sure that works
template <class T, class ... Types, class = typename
std::enable_if<std::is_base_of<IUnknown, T>::value>::type>
class WithCOMptrbase
?
SFINAE through a default type after a variadic list?
2
(std::is_same_v<Types, TypeOther> || ...)
– Piotr Skotnicki
Nov 15 '18 at 18:28
1
Replacingclass = std::enable_if_t<(syd::is_same_v<Types... , TypeOther> || ...)>
withstd::enable_if_t<(syd::is_same_v<Types... , TypeOther> || ...), bool> =true
permits multiple ctor overloads. Also you have too many...
, trystd::enable_if_t<(syd::is_same_v<Types, TypeOther> || ...), bool> =true
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:28
@PiotrSkotnicki - Ops... not seen the one afterTypes
; thanks.
– max66
Nov 15 '18 at 18:33
1
@max66 Imagine they add a 2nd constructor which takes one templateT*
and a SFINAE "test" clause. With this design they conflict with annoying error messages; with the, bool> = true
design they don't I'm just suggesting a better default SFINAE "cargo cult" trick to always use to avoid a potential issue that may or may not apply in any given case.
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:53
1
@max66 Last I checked,void*
wasn't a valid type of a non-type template parameter, but I could imagine that had changed.
– Yakk - Adam Nevraumont
Nov 15 '18 at 20:43
|
show 10 more comments
How about CRTP to avoid some template:
template <typename Base, typename T>
class Impl
public:
Impl() = default;
explicit Impl(T*) static_cast<Base*>(this)->ptr_ = cQueryInterface<T>(ptr);
;
template <class T, class ... Ts>
class WithCOMptrbase : private Impl<WithCOMptrbase<T, Ts...>, Ts>...
static_assert(std::is_base_of<IUnknown, T>::value);
static_assert((std::is_base_of<IUnknown, Ts>::value && ...));
template <typename, typename> friend struct Impl; // We don't have variadic friend :/
protected:
T* ptr_ = nullptr;
public:
using Impl<WithCOMptrbase, Ts>::Impl...;
//construct smart pointer by copy
explicit WithCOMptrbase(T* ptr, bool AddRef = false) : ptr_(ptr)
if (AddRef) ptr_->AddRef();
//other methods
;
Did I correctly understand: In your case you will generate all the possible overloaded constructors, unlike generating them "on demand" as in template in another answer?
– Sergey Kolesnik
Nov 15 '18 at 20:34
Yes, that's the goal.
– Jarod42
Nov 15 '18 at 20:40
I get Error C3203: "unspecialized class template cannot be used as a template argument for template parameter". I also get "syntax error: '...' " for the line with ' static_assert((std::is_base_of<IUnknown, Ts>::value && ...));'
– Sergey Kolesnik
Nov 18 '18 at 17:32
@SergeyKolesnik: I fixed some typos.
– Jarod42
Nov 18 '18 at 17:54
add a comment |
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',
autoActivateHeartbeat: false,
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53325681%2flimit-allowed-com-interfaces-by-using-template-function-with-limited-variadic-pa%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Try with
template <class TypeOther, class =
std::enable_if_t<(std::is_same_v<Types, TypeOther> || ...)>>
WithCOMptrbase(TypeOther* ptr)
: ptr_(cQueryInterface<T>(ptr))
I mean... you're using three ellipsis instead of one (remove the ellipsis after ::value
and the one after Types
) and you need an additional couple of parentheses.
Off topic: are you sure that works
template <class T, class ... Types, class = typename
std::enable_if<std::is_base_of<IUnknown, T>::value>::type>
class WithCOMptrbase
?
SFINAE through a default type after a variadic list?
2
(std::is_same_v<Types, TypeOther> || ...)
– Piotr Skotnicki
Nov 15 '18 at 18:28
1
Replacingclass = std::enable_if_t<(syd::is_same_v<Types... , TypeOther> || ...)>
withstd::enable_if_t<(syd::is_same_v<Types... , TypeOther> || ...), bool> =true
permits multiple ctor overloads. Also you have too many...
, trystd::enable_if_t<(syd::is_same_v<Types, TypeOther> || ...), bool> =true
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:28
@PiotrSkotnicki - Ops... not seen the one afterTypes
; thanks.
– max66
Nov 15 '18 at 18:33
1
@max66 Imagine they add a 2nd constructor which takes one templateT*
and a SFINAE "test" clause. With this design they conflict with annoying error messages; with the, bool> = true
design they don't I'm just suggesting a better default SFINAE "cargo cult" trick to always use to avoid a potential issue that may or may not apply in any given case.
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:53
1
@max66 Last I checked,void*
wasn't a valid type of a non-type template parameter, but I could imagine that had changed.
– Yakk - Adam Nevraumont
Nov 15 '18 at 20:43
|
show 10 more comments
Try with
template <class TypeOther, class =
std::enable_if_t<(std::is_same_v<Types, TypeOther> || ...)>>
WithCOMptrbase(TypeOther* ptr)
: ptr_(cQueryInterface<T>(ptr))
I mean... you're using three ellipsis instead of one (remove the ellipsis after ::value
and the one after Types
) and you need an additional couple of parentheses.
Off topic: are you sure that works
template <class T, class ... Types, class = typename
std::enable_if<std::is_base_of<IUnknown, T>::value>::type>
class WithCOMptrbase
?
SFINAE through a default type after a variadic list?
2
(std::is_same_v<Types, TypeOther> || ...)
– Piotr Skotnicki
Nov 15 '18 at 18:28
1
Replacingclass = std::enable_if_t<(syd::is_same_v<Types... , TypeOther> || ...)>
withstd::enable_if_t<(syd::is_same_v<Types... , TypeOther> || ...), bool> =true
permits multiple ctor overloads. Also you have too many...
, trystd::enable_if_t<(syd::is_same_v<Types, TypeOther> || ...), bool> =true
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:28
@PiotrSkotnicki - Ops... not seen the one afterTypes
; thanks.
– max66
Nov 15 '18 at 18:33
1
@max66 Imagine they add a 2nd constructor which takes one templateT*
and a SFINAE "test" clause. With this design they conflict with annoying error messages; with the, bool> = true
design they don't I'm just suggesting a better default SFINAE "cargo cult" trick to always use to avoid a potential issue that may or may not apply in any given case.
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:53
1
@max66 Last I checked,void*
wasn't a valid type of a non-type template parameter, but I could imagine that had changed.
– Yakk - Adam Nevraumont
Nov 15 '18 at 20:43
|
show 10 more comments
Try with
template <class TypeOther, class =
std::enable_if_t<(std::is_same_v<Types, TypeOther> || ...)>>
WithCOMptrbase(TypeOther* ptr)
: ptr_(cQueryInterface<T>(ptr))
I mean... you're using three ellipsis instead of one (remove the ellipsis after ::value
and the one after Types
) and you need an additional couple of parentheses.
Off topic: are you sure that works
template <class T, class ... Types, class = typename
std::enable_if<std::is_base_of<IUnknown, T>::value>::type>
class WithCOMptrbase
?
SFINAE through a default type after a variadic list?
Try with
template <class TypeOther, class =
std::enable_if_t<(std::is_same_v<Types, TypeOther> || ...)>>
WithCOMptrbase(TypeOther* ptr)
: ptr_(cQueryInterface<T>(ptr))
I mean... you're using three ellipsis instead of one (remove the ellipsis after ::value
and the one after Types
) and you need an additional couple of parentheses.
Off topic: are you sure that works
template <class T, class ... Types, class = typename
std::enable_if<std::is_base_of<IUnknown, T>::value>::type>
class WithCOMptrbase
?
SFINAE through a default type after a variadic list?
edited Nov 15 '18 at 18:29
answered Nov 15 '18 at 18:27
max66max66
38.4k74473
38.4k74473
2
(std::is_same_v<Types, TypeOther> || ...)
– Piotr Skotnicki
Nov 15 '18 at 18:28
1
Replacingclass = std::enable_if_t<(syd::is_same_v<Types... , TypeOther> || ...)>
withstd::enable_if_t<(syd::is_same_v<Types... , TypeOther> || ...), bool> =true
permits multiple ctor overloads. Also you have too many...
, trystd::enable_if_t<(syd::is_same_v<Types, TypeOther> || ...), bool> =true
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:28
@PiotrSkotnicki - Ops... not seen the one afterTypes
; thanks.
– max66
Nov 15 '18 at 18:33
1
@max66 Imagine they add a 2nd constructor which takes one templateT*
and a SFINAE "test" clause. With this design they conflict with annoying error messages; with the, bool> = true
design they don't I'm just suggesting a better default SFINAE "cargo cult" trick to always use to avoid a potential issue that may or may not apply in any given case.
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:53
1
@max66 Last I checked,void*
wasn't a valid type of a non-type template parameter, but I could imagine that had changed.
– Yakk - Adam Nevraumont
Nov 15 '18 at 20:43
|
show 10 more comments
2
(std::is_same_v<Types, TypeOther> || ...)
– Piotr Skotnicki
Nov 15 '18 at 18:28
1
Replacingclass = std::enable_if_t<(syd::is_same_v<Types... , TypeOther> || ...)>
withstd::enable_if_t<(syd::is_same_v<Types... , TypeOther> || ...), bool> =true
permits multiple ctor overloads. Also you have too many...
, trystd::enable_if_t<(syd::is_same_v<Types, TypeOther> || ...), bool> =true
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:28
@PiotrSkotnicki - Ops... not seen the one afterTypes
; thanks.
– max66
Nov 15 '18 at 18:33
1
@max66 Imagine they add a 2nd constructor which takes one templateT*
and a SFINAE "test" clause. With this design they conflict with annoying error messages; with the, bool> = true
design they don't I'm just suggesting a better default SFINAE "cargo cult" trick to always use to avoid a potential issue that may or may not apply in any given case.
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:53
1
@max66 Last I checked,void*
wasn't a valid type of a non-type template parameter, but I could imagine that had changed.
– Yakk - Adam Nevraumont
Nov 15 '18 at 20:43
2
2
(std::is_same_v<Types, TypeOther> || ...)
– Piotr Skotnicki
Nov 15 '18 at 18:28
(std::is_same_v<Types, TypeOther> || ...)
– Piotr Skotnicki
Nov 15 '18 at 18:28
1
1
Replacing
class = std::enable_if_t<(syd::is_same_v<Types... , TypeOther> || ...)>
with std::enable_if_t<(syd::is_same_v<Types... , TypeOther> || ...), bool> =true
permits multiple ctor overloads. Also you have too many ...
, try std::enable_if_t<(syd::is_same_v<Types, TypeOther> || ...), bool> =true
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:28
Replacing
class = std::enable_if_t<(syd::is_same_v<Types... , TypeOther> || ...)>
with std::enable_if_t<(syd::is_same_v<Types... , TypeOther> || ...), bool> =true
permits multiple ctor overloads. Also you have too many ...
, try std::enable_if_t<(syd::is_same_v<Types, TypeOther> || ...), bool> =true
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:28
@PiotrSkotnicki - Ops... not seen the one after
Types
; thanks.– max66
Nov 15 '18 at 18:33
@PiotrSkotnicki - Ops... not seen the one after
Types
; thanks.– max66
Nov 15 '18 at 18:33
1
1
@max66 Imagine they add a 2nd constructor which takes one template
T*
and a SFINAE "test" clause. With this design they conflict with annoying error messages; with the , bool> = true
design they don't I'm just suggesting a better default SFINAE "cargo cult" trick to always use to avoid a potential issue that may or may not apply in any given case.– Yakk - Adam Nevraumont
Nov 15 '18 at 18:53
@max66 Imagine they add a 2nd constructor which takes one template
T*
and a SFINAE "test" clause. With this design they conflict with annoying error messages; with the , bool> = true
design they don't I'm just suggesting a better default SFINAE "cargo cult" trick to always use to avoid a potential issue that may or may not apply in any given case.– Yakk - Adam Nevraumont
Nov 15 '18 at 18:53
1
1
@max66 Last I checked,
void*
wasn't a valid type of a non-type template parameter, but I could imagine that had changed.– Yakk - Adam Nevraumont
Nov 15 '18 at 20:43
@max66 Last I checked,
void*
wasn't a valid type of a non-type template parameter, but I could imagine that had changed.– Yakk - Adam Nevraumont
Nov 15 '18 at 20:43
|
show 10 more comments
How about CRTP to avoid some template:
template <typename Base, typename T>
class Impl
public:
Impl() = default;
explicit Impl(T*) static_cast<Base*>(this)->ptr_ = cQueryInterface<T>(ptr);
;
template <class T, class ... Ts>
class WithCOMptrbase : private Impl<WithCOMptrbase<T, Ts...>, Ts>...
static_assert(std::is_base_of<IUnknown, T>::value);
static_assert((std::is_base_of<IUnknown, Ts>::value && ...));
template <typename, typename> friend struct Impl; // We don't have variadic friend :/
protected:
T* ptr_ = nullptr;
public:
using Impl<WithCOMptrbase, Ts>::Impl...;
//construct smart pointer by copy
explicit WithCOMptrbase(T* ptr, bool AddRef = false) : ptr_(ptr)
if (AddRef) ptr_->AddRef();
//other methods
;
Did I correctly understand: In your case you will generate all the possible overloaded constructors, unlike generating them "on demand" as in template in another answer?
– Sergey Kolesnik
Nov 15 '18 at 20:34
Yes, that's the goal.
– Jarod42
Nov 15 '18 at 20:40
I get Error C3203: "unspecialized class template cannot be used as a template argument for template parameter". I also get "syntax error: '...' " for the line with ' static_assert((std::is_base_of<IUnknown, Ts>::value && ...));'
– Sergey Kolesnik
Nov 18 '18 at 17:32
@SergeyKolesnik: I fixed some typos.
– Jarod42
Nov 18 '18 at 17:54
add a comment |
How about CRTP to avoid some template:
template <typename Base, typename T>
class Impl
public:
Impl() = default;
explicit Impl(T*) static_cast<Base*>(this)->ptr_ = cQueryInterface<T>(ptr);
;
template <class T, class ... Ts>
class WithCOMptrbase : private Impl<WithCOMptrbase<T, Ts...>, Ts>...
static_assert(std::is_base_of<IUnknown, T>::value);
static_assert((std::is_base_of<IUnknown, Ts>::value && ...));
template <typename, typename> friend struct Impl; // We don't have variadic friend :/
protected:
T* ptr_ = nullptr;
public:
using Impl<WithCOMptrbase, Ts>::Impl...;
//construct smart pointer by copy
explicit WithCOMptrbase(T* ptr, bool AddRef = false) : ptr_(ptr)
if (AddRef) ptr_->AddRef();
//other methods
;
Did I correctly understand: In your case you will generate all the possible overloaded constructors, unlike generating them "on demand" as in template in another answer?
– Sergey Kolesnik
Nov 15 '18 at 20:34
Yes, that's the goal.
– Jarod42
Nov 15 '18 at 20:40
I get Error C3203: "unspecialized class template cannot be used as a template argument for template parameter". I also get "syntax error: '...' " for the line with ' static_assert((std::is_base_of<IUnknown, Ts>::value && ...));'
– Sergey Kolesnik
Nov 18 '18 at 17:32
@SergeyKolesnik: I fixed some typos.
– Jarod42
Nov 18 '18 at 17:54
add a comment |
How about CRTP to avoid some template:
template <typename Base, typename T>
class Impl
public:
Impl() = default;
explicit Impl(T*) static_cast<Base*>(this)->ptr_ = cQueryInterface<T>(ptr);
;
template <class T, class ... Ts>
class WithCOMptrbase : private Impl<WithCOMptrbase<T, Ts...>, Ts>...
static_assert(std::is_base_of<IUnknown, T>::value);
static_assert((std::is_base_of<IUnknown, Ts>::value && ...));
template <typename, typename> friend struct Impl; // We don't have variadic friend :/
protected:
T* ptr_ = nullptr;
public:
using Impl<WithCOMptrbase, Ts>::Impl...;
//construct smart pointer by copy
explicit WithCOMptrbase(T* ptr, bool AddRef = false) : ptr_(ptr)
if (AddRef) ptr_->AddRef();
//other methods
;
How about CRTP to avoid some template:
template <typename Base, typename T>
class Impl
public:
Impl() = default;
explicit Impl(T*) static_cast<Base*>(this)->ptr_ = cQueryInterface<T>(ptr);
;
template <class T, class ... Ts>
class WithCOMptrbase : private Impl<WithCOMptrbase<T, Ts...>, Ts>...
static_assert(std::is_base_of<IUnknown, T>::value);
static_assert((std::is_base_of<IUnknown, Ts>::value && ...));
template <typename, typename> friend struct Impl; // We don't have variadic friend :/
protected:
T* ptr_ = nullptr;
public:
using Impl<WithCOMptrbase, Ts>::Impl...;
//construct smart pointer by copy
explicit WithCOMptrbase(T* ptr, bool AddRef = false) : ptr_(ptr)
if (AddRef) ptr_->AddRef();
//other methods
;
edited Nov 18 '18 at 17:53
answered Nov 15 '18 at 19:38
Jarod42Jarod42
119k12104189
119k12104189
Did I correctly understand: In your case you will generate all the possible overloaded constructors, unlike generating them "on demand" as in template in another answer?
– Sergey Kolesnik
Nov 15 '18 at 20:34
Yes, that's the goal.
– Jarod42
Nov 15 '18 at 20:40
I get Error C3203: "unspecialized class template cannot be used as a template argument for template parameter". I also get "syntax error: '...' " for the line with ' static_assert((std::is_base_of<IUnknown, Ts>::value && ...));'
– Sergey Kolesnik
Nov 18 '18 at 17:32
@SergeyKolesnik: I fixed some typos.
– Jarod42
Nov 18 '18 at 17:54
add a comment |
Did I correctly understand: In your case you will generate all the possible overloaded constructors, unlike generating them "on demand" as in template in another answer?
– Sergey Kolesnik
Nov 15 '18 at 20:34
Yes, that's the goal.
– Jarod42
Nov 15 '18 at 20:40
I get Error C3203: "unspecialized class template cannot be used as a template argument for template parameter". I also get "syntax error: '...' " for the line with ' static_assert((std::is_base_of<IUnknown, Ts>::value && ...));'
– Sergey Kolesnik
Nov 18 '18 at 17:32
@SergeyKolesnik: I fixed some typos.
– Jarod42
Nov 18 '18 at 17:54
Did I correctly understand: In your case you will generate all the possible overloaded constructors, unlike generating them "on demand" as in template in another answer?
– Sergey Kolesnik
Nov 15 '18 at 20:34
Did I correctly understand: In your case you will generate all the possible overloaded constructors, unlike generating them "on demand" as in template in another answer?
– Sergey Kolesnik
Nov 15 '18 at 20:34
Yes, that's the goal.
– Jarod42
Nov 15 '18 at 20:40
Yes, that's the goal.
– Jarod42
Nov 15 '18 at 20:40
I get Error C3203: "unspecialized class template cannot be used as a template argument for template parameter". I also get "syntax error: '...' " for the line with ' static_assert((std::is_base_of<IUnknown, Ts>::value && ...));'
– Sergey Kolesnik
Nov 18 '18 at 17:32
I get Error C3203: "unspecialized class template cannot be used as a template argument for template parameter". I also get "syntax error: '...' " for the line with ' static_assert((std::is_base_of<IUnknown, Ts>::value && ...));'
– Sergey Kolesnik
Nov 18 '18 at 17:32
@SergeyKolesnik: I fixed some typos.
– Jarod42
Nov 18 '18 at 17:54
@SergeyKolesnik: I fixed some typos.
– Jarod42
Nov 18 '18 at 17:54
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53325681%2flimit-allowed-com-interfaces-by-using-template-function-with-limited-variadic-pa%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Unless you restrict what version of C++, we'll assume c++17 at this point. Especially because it makes it easier to solve. :)
– Yakk - Adam Nevraumont
Nov 15 '18 at 18:23
Second, what goes wrong with your solution? A syntax error in
WithCOMptrbase
?– Yakk - Adam Nevraumont
Nov 15 '18 at 18:25
Do you want the stored TypeOther to support all of the interfaces, or one of the interfaces? One seems strange. Ah, you want only poitners of
T
or` Types...` to be permited, and then you want to always store it as aT
? Sort of like a variant but no way to go back to the type stored.– Yakk - Adam Nevraumont
Nov 15 '18 at 18:29
@Yakk-AdamNevraumont I want to support All of the provided interfaces.
– Sergey Kolesnik
Nov 15 '18 at 18:35
2
@Yakk-AdamNevraumont, the Idea is to allow passing only the provided Interfaces, so in my case I would be able to construct WithCOMptrbase only when "IThis, IInterface1, IInterface2, IInterface3" types are passed as arguments. For now I successfully compile with those allowed tyes and get compile error for other (not allowed) interfaces.
– Sergey Kolesnik
Nov 15 '18 at 19:01