template<class T, class... TA> Uptr<T, TA> makeUniquePtr(/*...*/) { /*...*/ };
template<class T, class... TA> Sptr<T, TA> makeSharedPtr(/*...*/) { /*...*/ };
template<typename TFPType, TFPType TFP> void func(/*...*/) { /*...*/ }
template<class T, class... TA> void implementation1(/*...*/)
{
// Can this be reduced to func<&makeUniquePtr, T, TA...>?
func<decltype(&makeUniquePtr<T, TA...>), &makeUniquePtr<T, TA...>>(/*...*/);
}
template<class T, class... TA> void implementation2(/*...*/)
{
// Can this be reduced to func<&makeSharedPtr, T, TA...>?
func<decltype(&makeSharedPtr<T, TA...>), &makeSharedPtr<T, TA...>>(/*...*/);
}
Calling func</*...*/>(/*...*/)
is extremely verbose. Is there a way to simply call
func<&makeSharedPtr, T, TA...>(/*...*/)
and internally use
&makeSharedPtr<T, TA...>
without having the user specify it twice?
Create a shared maker stateless function object class, like std::less
, but with no template
parameters itself: instead operator()
perfect forwards to your template
function.
Pass it instead of your function pointer.
If you need template
arguments passed to it, either create a static
method to it, or make the entire template class
take the arguments and use them in the operator()
.
Here is an example of late-bound template
arguments (live example):
#include <iostream>
// test stubs:
template<typename... Ts>
using UPtr = int;
template<typename... Ts>
using SPtr = double;
template<typename T, typename...TA>
UPtr<T,TA...> makeUniquePtr() {
std::cout << "makeUniquePtr\n";
return {};
}
template<typename T, typename...TA>
SPtr<T,TA...> makeSharedPtr() {
std::cout << "makeSharedPtr\n";
return {};
}
// perfect forwarding make static functions passed by class name:
struct unique_ptr_maker {
template<typename T, typename...TA, typename...Args>
static UPtr<T, TA...> make(Args&&...args) {
return makeUniquePtr<T, TA...>( std::forward<Args>(args)... );
}
};
struct shared_ptr_maker {
template<typename T, typename...TA, typename...Args>
static SPtr<T, TA...> make(Args&&...args) {
return makeSharedPtr<T, TA...>( std::forward<Args>(args)... );
}
};
// your `func`. It can take args or whatever:
template<typename maker, class T, class... TA> void func() {
std::cout << "func\n";
maker::template make<T, TA...>();
}
// a sample of implementation 1 and 2:
template<class T, class... TA> void implementation1()
{
func<unique_ptr_maker, T, TA...>();
}
template<class T, class... TA> void implementation2()
{
func<shared_ptr_maker, T, TA...>();
}
// and, to test, always instantiate:
int main() {
implementation1<int, double>();
implementation2<int, char>();
return 0;
}
with much of the functionality stubbed out, as you did not detail what it was supposed to do in your question.
Making a few assumptions on intended use from your names, I would try something like this:
template<class T>
struct makeUniquePtr {
template<class... TA>
Uptr<T, TA> operator()(TA&&...) const { /*...*/ }
};
template<class T>
struct makeSharedPtr {
template<class... TA>
Sptr<T, TA> operator()(TA&&...) const { /*...*/ }
};
template<class F> void func(/*...*/) { /*...*/ }
template<class T, class... TA> void implementation1(/*...*/)
{
func<makeUniquePtr<T>>(/*...*/);
}
template<class T, class... TA> void implementation2(/*...*/)
{
func<makeSharedPtr<T>>(/*...*/);
}
Unlike Yakk's solution, here parameters TA...
are automatically deduced, as is the case for std::make_unique etc.
EDIT My reference to Yakk's solution was made before that solution was edited. I now see it is expanded.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With