Limit allowed COM Interfaces by using template function with limited variadic parameters (std::is_same)










2















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.










share|improve this question
























  • 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 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






  • 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















2















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.










share|improve this question
























  • 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 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






  • 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













2












2








2








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.










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 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












  • @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












  • 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












  • @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












2 Answers
2






active

oldest

votes


















4














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?






share|improve this answer




















  • 2





    (std::is_same_v<Types, TypeOther> || ...)

    – Piotr Skotnicki
    Nov 15 '18 at 18:28






  • 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












  • @PiotrSkotnicki - Ops... not seen the one after Types; thanks.

    – max66
    Nov 15 '18 at 18:33






  • 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






  • 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



















1














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
;





share|improve this answer

























  • 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










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
);



);













draft saved

draft discarded


















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









4














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?






share|improve this answer




















  • 2





    (std::is_same_v<Types, TypeOther> || ...)

    – Piotr Skotnicki
    Nov 15 '18 at 18:28






  • 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












  • @PiotrSkotnicki - Ops... not seen the one after Types; thanks.

    – max66
    Nov 15 '18 at 18:33






  • 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






  • 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
















4














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?






share|improve this answer




















  • 2





    (std::is_same_v<Types, TypeOther> || ...)

    – Piotr Skotnicki
    Nov 15 '18 at 18:28






  • 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












  • @PiotrSkotnicki - Ops... not seen the one after Types; thanks.

    – max66
    Nov 15 '18 at 18:33






  • 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






  • 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














4












4








4







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?






share|improve this answer















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?







share|improve this answer














share|improve this answer



share|improve this answer








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





    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






  • 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






  • 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





    (std::is_same_v<Types, TypeOther> || ...)

    – Piotr Skotnicki
    Nov 15 '18 at 18:28






  • 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












  • @PiotrSkotnicki - Ops... not seen the one after Types; thanks.

    – max66
    Nov 15 '18 at 18:33






  • 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






  • 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














1














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
;





share|improve this answer

























  • 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















1














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
;





share|improve this answer

























  • 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













1












1








1







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
;





share|improve this answer















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
;






share|improve this answer














share|improve this answer



share|improve this answer








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

















  • 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

















draft saved

draft discarded
















































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.




draft saved


draft discarded














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





















































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







這個網誌中的熱門文章

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