I need to determine at compile time if an abstract class T (passed in as a template parameter) has a protected or private parameterless constructor. Because T is abstract, all the versions of the std::is_constructible<T> family return false no matter what.
I've tried defining a class U that inherits from the class in question, has using T::T, and is concrete; unfortunately, I've found the using directive ignores the default constructor;
(I need this for SFINAE purposes; I need to make my templated concrete-version-of-T factory refuse to work for T with explicitly inaccessible constructors.)
This is what I'm trying to make happen:
#include <iostream>
#include <utility>
template <typename T, typename... Args>
static T* make(Args&&...);
class Base {
public:
void ImportantFunctionThatRequiresFactorySupport();
private:
class InstantiationToken {};
virtual InstantiationToken* NoInstantiationForYou() = 0;
template <typename T>
class Deabstractifier final : public T {
private:
InstantiationToken* NoInstantiationForYou() { return NULL; }
};
template <typename T, typename... Args>
friend T* make(Args&&...);
};
template <typename T, typename... Args>
static T* make(Args&&... args) {
// There should be a static_assert here to detect when T has a protected constructor and refuse to make one
return new Base::Deabstractifier<T>(std::forward<Args>(args)...);
}
class IntermediateDerivedThatIsFineToConstruct : public Base {
public:
IntermediateDerivedThatIsFineToConstruct() = default;
void DoSomethingOrdinaryAndCompletelyReasonable() {
ImportantFunctionThatRequiresFactorySupport();
}
};
class IntermediateDerivedThatShouldOnlyBeInheritedFrom : public Base {
protected:
IntermediateDerivedThatShouldOnlyBeInheritedFrom() = default;
public:
void SomethingElseCompletelyReasonable() {
ImportantFunctionThatRequiresFactorySupport();
}
};
class ThingThatShouldBeConstructibleAgain : public IntermediateDerivedThatShouldOnlyBeInheritedFrom {
public:
void SomeExtaFunctionality() {};
};
int main()
{
std::cout << "Starting..." << std::endl;
make<IntermediateDerivedThatIsFineToConstruct>(); // Should succeed
std::cout << "Did thing 1" << std::endl;
make<ThingThatShouldBeConstructibleAgain>(); // Should succeed
std::cout << "Did thing 2" << std::endl;
make<IntermediateDerivedThatShouldOnlyBeInheritedFrom>(); // Should fail at compile time
std::cout << "Did thing 3" << std::endl;
}
live on coliru
Related
I have a template class and a member function print() to print the data.
template<typename T>
class A
{
public:
T data;
void print(void)
{
std::cout << data << std::endl;
}
// other functions ...
};
Then, I want to either print scalar data or vector data, so I give a specialized definition and get a compiler error.
template<typename T>
void A<std::vector<T>>::print(void) // template argument list error
{
for (const auto& d : data)
{
std::cout << d << std::endl;
}
}
Question: Why does this member function specialization get an error? What is the correct way to define a print function for a vector?
Solution 1: I have tested the following definition.
template<typename T>
class A<std::vector<T>>
{
public:
std::vector<T> data;
void print(void) { // OK
// ...
}
}
This one worked, but I have to copy the other member functions into this specialized class.
EDIT:
Solution 2: To prevent copy all the other member functions, I define a base class containing the common member functions and inherit from the base class:
template<typename T>
class Base
{
public:
T data;
// other functions ...
};
template<typename T>
class A : public Base<T>
{
public:
void print(void)
{
std::cout << this->data << std::endl;
}
};
template<typename T>
class A<std::vector<T>> : public Base<std::vector<T>>
{
public:
void print(void)
{
for (const auto& d : this->data)
{
std::cout << d << std::endl;
}
}
};
This solution works well. Are there some better or more conventional solutions?
Why does this member function specialization get error?
When you instantiate the template class A for example A<std::vector<int>>, the template parameter T is equal to std::vector<int>, not std::vector<T>, and this a specialization case of the function. Unfortunately this can not be done with member functions as mentioned in the comments.
Are there some better solutions?
Yes; In c++17 you could use if constexpr with a trait to check the std::vector, like this.
#include <type_traits> // std::false_type, std::true_type
#include <vector>
// traits for checking wether T is a type of std::vector<>
template<typename T> struct is_std_vector final : std::false_type {};
template<typename... T> struct is_std_vector<std::vector<T...>> final : std::true_type {};
template<typename T>
class A /* final */
{
T mData;
public:
// ...constructor
void print() const /* noexcept */
{
if constexpr (is_std_vector<T>::value) // when T == `std::vector<>`
{
for (const auto element : mData)
std::cout << element << "\n";
}
else // for types other than `std::vector<>`
{
std::cout << mData << std::endl;
}
}
};
(See Live Online)
This way you keep only one template class and the print() will instantiate the appropriate part according to the template type T at compile time.
If you don not have access to C++17, other option is to SFINAE the members(Since c++11).
#include <type_traits> // std::false_type, std::true_type, std::enbale_if
#include <vector>
// traits for checking wether T is a type of std::vector<>
template<typename T> struct is_std_vector final : std::false_type {};
template<typename... T> struct is_std_vector<std::vector<T...>> final : std::true_type {};
template<typename T>
class A /* final */
{
T mData;
public:
// ...constructor
template<typename Type = T> // when T == `std::vector<>`
auto print() const -> typename std::enable_if<is_std_vector<Type>::value>::type
{
for (const auto element : mData)
std::cout << element << "\n";
}
template<typename Type = T> // for types other than `std::vector<>`
auto print() const -> typename std::enable_if<!is_std_vector<Type>::value>::type
{
std::cout << mData << std::endl;
}
};
(See Live Online)
What if I have more other data types like self-define vector classes
or matrices? Do I have to define many is_xx_vector?
You can check the type is a specialization of the provided one like as follows. This way you can avoid providing many traits for each type. The is_specialization is basically inspired from this post
#include <type_traits> // std::false_type, std::true_type
#include <vector>
// custom MyVector (An example)
template<typename T> struct MyVector {};
template<typename Test, template<typename...> class ClassType>
struct is_specialization final : std::false_type {};
template<template<typename...> class ClassType, typename... Args>
struct is_specialization<ClassType<Args...>, ClassType> final : std::true_type {};
And the print function could be in c++17:
void print() const /* noexcept */
{
if constexpr (is_specialization<T, std::vector>::value)// when T == `std::vector<>`
{
for (const auto element : mData)
std::cout << element << "\n";
}
else if constexpr (is_specialization<T, ::MyVector>::value) // custom `MyVector`
{
std::cout << "MyVector\n";
}
else // for types other than `std::vector<>` and custom `MyVector`
{
std::cout << mData << std::endl;
}
}
(See Live Online)
You need to implement a template class that uses a vector as template parameter. This worked for me.
template<typename T>
class A
{
public:
T data;
void print(void) {
std::cout << "Data output" << std::endl;
}
// other functions ...
};
template <typename T>
class A<std::vector<T>>
{
public:
std::vector<T> data;
void print() {
for (auto i : data) {
std::cout << "Vector output" << std::endl;
}
}
};
You could always use named tag dispatching to check if type provided by template user is vector.
A<std::vector<T>> notation won't work as you both try to take into account that T is type and vector of types which is contradicting with itself.
Below is code I used named tag dispatching as solution to your problem:
#include <iostream>
#include <vector>
#include <type_traits>
using namespace std;
template<typename T> struct is_vector : public std::false_type {};
template<typename T, typename A>
struct is_vector<std::vector<T, A>> : public std::true_type {};
template<typename T>
class A
{
public:
T data;
void print(std::true_type) {
for (auto& a : data) { std::cout << a << std::endl; }
}
void print(std::false_type) {
std::cout << data << std::endl;
}
void print() {
print(is_vector<T>{});
}
};
int main()
{
A<int> a;
a.data = 1;
a.print();
A<std::vector<int>> b;
b.data = { 1, 2 ,3 ,4 ,5 };
b.print();
return 0;
}
Succesfully compiled with https://www.onlinegdb.com/online_c++_compiler
Based on answer: Check at compile-time is a template type a vector
You can dispatch printing to another member function (static or not). For example:
template<typename T>
class A {
public:
T data;
void print() const {
print_impl(data);
}
private:
template<class S>
static void print_impl(const S& data) {
std::cout << data;
}
template<class S, class A>
static void print_impl(const std::vector<S, A>& data) {
for (const auto& d : data)
std::cout << d;
}
};
I have a variadic template class which takes two fixed template parameters and additionally a variable list of parameters.
When I create an instance I want to specify the first two parameters and have the rest deduced from the arguments passed to the ctor.
But it does not work, the variadic part seems always to be empty. I can only create an instance when I specify all the types (including the ctor arguments).
Here is the code I used for testing:
#include <iostream>
#include <tuple>
#include <string>
class Service
{
public:
virtual void Serve() = 0;
};
class InterfaceA : public Service {};
class InterfaceB : public Service {};
class InterfaceC : public Service {};
class ImplementationA : public InterfaceA
{
virtual void Serve() override
{
std::cout << "Implementation A: <null>";
}
};
class ImplementationB : public InterfaceB
{
public:
ImplementationB(int x)
: m_x(x)
{}
virtual void Serve() override
{
std::cout << "Implementation B: " << std::to_string(m_x);
}
private:
int m_x = 0;
};
class ImplementationC : public InterfaceC
{
public:
ImplementationC(std::string str)
: m_str(str)
{}
virtual void Serve() override
{
std::cout << "Implementation C: " << m_str;
}
private:
std::string m_str;
};
template <typename Interface, typename Implementation, typename... CtorArgs>
class Wrapper
{
public:
Wrapper(CtorArgs&&... args)
: m_ctorArgs(std::make_tuple(std::forward<CtorArgs>(args)...))
{}
Service& GetService()
{
m_service = std::apply([](CtorArgs ... ctorArgs)
{
return std::make_unique<Implementation>(ctorArgs...);
},
m_ctorArgs);
return *m_service;
}
private:
std::tuple<CtorArgs ...> m_ctorArgs;
std::unique_ptr<Service> m_service;
};
// deduction guide, not working...
template <typename Interface, typename Implementation, typename... CtorArgs>
Wrapper(int x)->Wrapper<Interface, Implementation, int>;
int main()
{
Wrapper<InterfaceA, ImplementationA> wrapperA;
wrapperA.GetService().Serve();
std::cout << "\n";
// Wrapper<InterfaceB, ImplementationB> wrapperB(7); // NOT OK
Wrapper<InterfaceB, ImplementationB, int> wrapperB(7); // OK
wrapperB.GetService().Serve();
std::cout << "\n";
}
I want to specify services, but create them on demand, when they are needed (due to dependencies between services). I already use factory methods in production code (wrappers which know what parameters to pass to service ctor), but in test code, I want to be able to quickly create a wrapper for mocks and dummy services, which might need different parameters as the production service.
I also tried to specify a deduction guide, but it seems to have no effect...
You might use template constructor, and std::function as factory:
template <typename Interface, typename Implementation>
class Wrapper
{
public:
template <typename... CtorArgs>
Wrapper(CtorArgs&&... args)
: m_factory([=](){return std::make_unique<Implementation>(ctorArgs...);})
{}
Service& GetService()
{
m_service = m_factory();
return *m_service;
}
private:
std::function<std::unique_ptr<Service>()> m_factory;
std::unique_ptr<Service> m_service;
};
Deduction guide is useless as it should be used to deduce all parameters.
It is all or nothing for providing template parameters.
But you could do:
Wrapper<InterfaceB, ImplementationB> wrapperB(7); // Ok
The deduction guide "should" be
template<typename Interface, typename Implementation, typename... CtorArgs>
Wrapper(CtorArgs&&... x)->Wrapper<Interface, Implementation, CtorArgs...>;
but this doesn't work, since Interface and Implementation are non-deducible.
I'd recommend following the standard library and using a factory function instead:
template<typename Interface, typename Implementation, typename... Args>
Wrapper<Interface, Implementation, Args...> make_wrapper(Args&&... args) {
return Wrapper<Interface, Implementation, Args...>(std::forward<Args>(args)...);
}
int main() {
auto wrapperA = make_wrapper<InterfaceA, ImplementationA>();
wrapperA.GetService().Serve();
std::cout << "\n";
}
Another solution is to add dummy parameters to Wrapper::Wrapper
template<typename T>
struct type_t { };
template<typename T>
constexpr inline type_t<T> type{};
template<typename Interface, typename Implementation, typename... CtorArgs>
class Wrapper {
public:
Wrapper(type_t<Interface>, type_t<Implementation>, CtorArgs&&... args)
: m_ctorArgs(std::make_tuple(std::forward<CtorArgs>(args)...))
{}
// ...
};
// not needed anymore, is implicit
// template<typename Interface, typename Implementation, typename... CtorArgs>
// Wrapper(type_t<Interface>, type_t<Implementation>, CtorArgs&&... x)->Wrapper<Interface, Implementation, CtorArgs...>;
int main() {
Wrapper wrapperB(type<InterfaceB>, type<ImplementationB>, 7);
wrapperB.GetService().Serve();
std::cout << "\n";
}
There's also this OCaml inspired thing:
template<typename Interface, typename Implementation>
struct Wrapper {
template<typename... Args>
class type {
public:
type(Args&&... args)
: m_ctorArgs(std::make_tuple(std::forward<Args>(args)...))
{}
// ...
};
};
int main() {
std::string s("Hello!");
// There's a spot of weirdness here: passing s doesn't work because then you end up trying to store a reference to s in the tuple
// perhaps the member tuple should actually be std::tuple<std::remove_cvref<Args>...>
Wrapper<InterfaceC, ImplementationC>::type wrapperC(std::move(s));
wrapperC.GetService().Serve();
std::cout << "\n";
}
Side note: Service::~Service() should probably be virtual.
Is it possible to create a class template with a member function definition only if the object created is of a specific type?
I've created a template class I will use for storing either int or doubles, but for doubles I would like to be able to set precision too (objects created with myclass < double> should have this functionality, but for myclass< int> there is no need for that to be present at all).
I know I can use a base class template, and create new classes "myInt", "myDouble" using that and implement the functionality only in the myDouble class, but I think it would be cleaner to define the functionality (both the function and a member variable) for doubles in the class template, if that's possible and preferable?
Let's add an example to show what I want to do:
#include <iostream>
#include <iomanip>
class commonBase{
public:
void setState(int state);
virtual void print() = 0;
private:
int _my_state;
};
template <typename T>
class generalObject : public commonBase {
public:
void value(T value);
void print(){ std::cout << "My value: " << _my_value << std::endl; }
private:
T _my_value;
};
template <typename T>
void generalObject<T>::value(T value){
_my_value = value;
}
// Is there any way do specialize only only whats different from the generalObject template?
// Here I thought I could specialize the case where a generalObject is created of <double>, but
// when I do, nothing is derived from generalObject (or at least not visible as far as I can tell)
template<>
class generalObject<double>{
public:
void setPrecision(int precision){ _my_precision = precision; }
// here I would like a special implementation of print(), which overrides the print() in generalObject
// and instead also prints according to the precision set when the object is of <double> type.
// Row below an example which doesn't work (compiler error, _my_value undefined)
void print(){ std::cout << "My value: " << std::setprecision(_my_precision) << _my_value << std::endl; }
private:
int _my_precision;
};
int main(int argc, char* argv[]){
generalObject<int> o1;
o1.value(1);
o1.print();
o1.setState(1); //inherited from the commonBase
generalObject<double> o2;
o2.setPrecision(2);
o2.value(2); //here value isn't available (compile error)
o2.print();
o2.setState(123); //also isn't available (compile error)
}
Sure.
template <typename T> class Poly;
void set_precision(Poly<double>* self, int a) {};
If you really want dot notation you can then add:
template <typename T> class Poly {
public: void set_precision(int a){::set_precision(this,a);}
...
However I think you should think about what you're trying to accomplish. If MyInt and MyDouble have different fields and different methods and different implementations, they should probably be different classes.
This can be solved using template specialization.
We first define a common template...
template< typename T >
struct myclass
{
// common stuff
};
... and specialize that for double:
template<>
struct myclass<double>
{
int precision = 10;
void setprecision( int p ){ precision = p; }
};
Now the setprecision() method can only be called for myclass<double>. The compiler will complain if we try to call it for anything else, like myclass<int>.
int main()
{
myclass<double> d;
d.setprecision( 42 ); // compiles
myclass<int> i;
i.setprecision( 42 ); // fails to compile, as expected
}
Demo.
The basic way to have a member function of a class template exist only for some template parameters is to create a specialization of the class template for those template parameters.
template<typename T>class X{
// general definition
};
template<>class X<double>{
// double-specific definition
};
The downside of this is that the specialization will need to duplicate anything that is common. One way to address this is to move the common things out to a base class template:
template<typename T>class Xcommon{
// common stuff
};
template<typename T>class X: public Xcommon<T>{
// general definition
};
template<>class X<double>: public Xcommon<double>{
// double-specific definition
};
Alternatively, you can do it the other way: put the common stuff in the derived class, and the extras in the base, and specialize the base:
template<typename T>class Xextras{
// empty by default
};
template<typename T>class X: public Xextras<T>{
// common definition
};
template<>class Xextras<double>{
// double-specific definition
};
Either way can work; which is better depends on the details.
Both these methods work for data members and member functions.
Alternatively, you can use enable_if to mean that member functions are not selected by overload resolution if the template parameter doesn't meet a required condition. This requires that the member function is itself a template.
template<typename T>class X{
template<typename U=T> // make it a template,
std::enable_if<std::is_same_v<U,double>> double_specific_function(){
// do stuff
}
};
I wouldn't recommend this option unless there is no other choice.
If the question is about a member function, then here is one of the ways to do it without class template specialization:
#include <iostream>
#include <type_traits>
template <typename T>
struct Type {
template <typename U = T,
typename = typename std::enable_if<std::is_same<U, double>::value>::type>
void only_for_double() {
std::cout << "a doubling" << std::endl;
}
};
int main() {
Type<int> n;
Type<double> d;
// n.only_for_double(); // does not compile.
d.only_for_double();
}
Example on ideone.com
If you require a data-member presence based on the template parameter, you will have to do some kind of specialization, in which case it is, probably, simpler to put the function into corresponding specialization.
EDIT: After OP made his question more specific
Here is one way to do it without extra class and getting rid of virtual functions. Hope it helps.
#include <iostream>
#include <iomanip>
template <typename T, typename Derived = void>
class commonBase {
public:
void setState(int state) {
_my_state = state;
}
void value(T value) {
_my_value = value;
}
template <typename U = Derived,
typename std::enable_if<std::is_same<U, void>::value,
void * >::type = nullptr>
void print() const {
std::cout << "My value: " << _my_value << std::endl;
}
template <typename U = Derived,
typename std::enable_if<!std::is_same<U, void>::value,
void * >::type = nullptr>
void print() const {
static_cast<Derived const *>(this)->_print();
}
protected:
T _my_value;
int _my_state;
};
template <typename T>
class generalObject : public commonBase<T> {
};
template<>
class generalObject<double> : public commonBase<double, generalObject<double>> {
private:
friend commonBase<double, generalObject<double>>;
void _print() const {
std::cout << "My value: " << std::setprecision(_my_precision) <<
_my_value << std::endl;
}
public:
void setPrecision(int precision){ _my_precision = precision; }
private:
int _my_precision;
};
int main(){
generalObject<int> o1;
o1.value(1);
o1.print();
o1.setState(1);
generalObject<double> o2;
o2.setPrecision(2);
o2.value(1.234);
o2.print();
o2.setState(123);
}
Same code on ideone.com
I need to check if a class C has a default constructor, either implicit or custom, and either public, protected or private.
I tried using std::is_default_constructible<C>::value, which returns true if C has a public default constructor (either implicit or custom) but false if C has a protected or private default constructor (seams to be the standard behavior though.)
Is there any way to check if a class has a protected or private default constructor ?
Note (if this may help): the check is performed from a function that is friend of the class C to be checked.
I need to perform this check in order to default-construct objects corresponding to the nullptr pointers of the m_objs tuple, member of a Foo object (partial Foo definition below):
template<class... Objects>
class Foo
{
public:
Foo(Objects*... objects)
: m_objs(objects...)
{
// User construct a Foo objects passing a pack of pointers
// some of them are nullptr, some are not.
// The following call should default-construct objects corresponding
// to the null pointers of m_objs member tuple:
objs_ctor<Objects...>();
}
private:
template<class Obj, class O1, class ...On>
void objs_ctor()
{
objs_ctor<Obj>(); objs_ctor<O1, On...>();
}
template<class Obj>
typename std::enable_if<std::is_default_constructible<Obj>::value, void>::type
objs_ctor()
{
Obj*& obj = std::get<Obj*>(m_objs);
if (obj == nullptr)
obj = new Obj; // default-construct Obj
}
template<class Obj>
typename std::enable_if<!std::is_default_constructible<Obj>::value, void>::type
objs_ctor()
{
Obj*& obj = std::get<Obj*>(m_objs);
assert(obj != nullptr); // terminate if not pre-constructed
}
private:
std::tuple<Objects*...> m_objs;
};
which is intended to be used as:
struct A { };
class B {
B() = default;
template <class... Ts>
friend class Foo;
};
int main() {
// currently asserts, even though Foo<A,B> is a friend of B
// and B is default-constructible to its friends
Foo<A, B> foo(nullptr, nullptr);
}
Example above asserts because std::is_default_constructible<B>::value is false, even though B has a [private] default ctor and Foo<A,B> is friend of B.
I will present a simplified example to make things easier. Then you can adapt it to your Foos class. The idea is to specialise my templated friend class as follows
#include <iostream>
// forward declaration
template <class... T>
struct Friend;
struct testing_tag;
// specialisation simply to check if default constructible
template <class T>
struct Friend<T, testing_tag> {
// sfinae trick has to be nested in the Friend class
// this candidate will be ignored if X does not have a default constructor
template <class X, class = decltype(X())>
static std::true_type test(X*);
template <class X>
static std::false_type test(...);
static constexpr bool value = decltype(test<T>(0))::value;
};
Notice that the std::true_type candidate will always be valid as long as X has a default constructor regardless if it is private, protected or public. Now test it
class default_public {
template <class... T>
friend struct Friend;
};
class default_protected {
template <class... T>
friend struct Friend;
protected:
default_protected() {}
};
class default_private {
template <class... T>
friend struct Friend;
private:
default_private() {}
};
class no_default {
public:
no_default(int x){}
};
// a convenient name to test with
template <class T>
using has_any_default_constructor = Friend<T, testing_tag>;
int main() {
std::cout << has_any_default_constructor<default_public>::value << std::endl;
std::cout << has_any_default_constructor<default_protected>::value << std::endl;
std::cout << has_any_default_constructor<default_private>::value << std::endl;
std::cout << has_any_default_constructor<no_default>::value << std::endl;
}
The problem is that if a class has neither public, nor protected nor private default constructor, the simple default definition of an instance gives a compilation error, not a run-time exception. So the test is simple: if this expression in a friend function C c;compiles, the class has a default ctor, either public, protected or private.
Just see example code:
#include <iostream>
#include <string>
class Cwith {
private:
std::string name;
Cwith(): name("default ctor") {}
friend void build();
};
class Cwithout {
private:
std::string name;
Cwithout(const std::string& name): name(name) {};
friend void build();
};
void build() {
Cwith cw;
std::cout << cw.name << std::endl;
Cwithout cwo; // error : class Cwithout has no defaut constructor
std::cout << cwo.name << std::endl;
}
int main() {
build();
return 0;
}
But I could not imagine a run-time test...
My understanding is that you want to check if your friend can default construct a class. The trick is that you have to have SFINAE inside the scope of the friend function. To do that, you need templates. To have local templates, you need generic lambdas.
We start with an overloader that we can pass multiple lambdas into. There may be a better way to write this:
template <class... Fs>
struct overload {
void operator()();
};
template <class F, class... Fs>
struct overload<F, Fs...> : F, overload<Fs...> {
overload(F&& f, Fs&&... fs)
: F(std::forward<F>(f))
, overload<Fs...>(std::forward<Fs>(fs)...)
{ }
using F::operator();
using overload<Fs...>::operator();
};
template <class... Fs>
overload<std::decay_t<Fs>...> make_overload(Fs&&... fs) {
return {std::forward<Fs>(fs)...};
}
Then you pass in overloaded, generic, SFINAE-d lambdas (C++14 required). Let's say we have:
struct Q {
friend void foo();
};
template <class T>
struct tag_t { using type = T; };
template <class T>
constexpr tag_t<T> tag{};
Then we could write:
void foo() {
auto f = make_overload(
[](auto x) -> decltype( typename decltype(x)::type(), void() ) {
Q q;
std::cout << "I can do it.\n";
},
[](...) {
std::cout << "What do you want here?\n";
});
f(tag<Q>, 0);
}
If works is a friend, the first overload is viable and preferred - so you get that, which constructs a Q because it can. If works is not a friend, the first overload is not viable and so you get the second overload.
The key is that we test the construction of Q (the typename decltype(x)::type() part) within works() - so it will either be covered by friendship.
So for your specific usage, that would be:
template <class Obj>
objs_ctor() {
Obj*& obj = std::get<Obj*>(m_objs);
auto ctor = make_overload(
[&](auto x) -> decltype( typename decltype(x)::type(), void() ) {
if (!obj) {
obj = new Obj;
}
},
[=](...) {
assert(obj);
});
ctor(tag<Obj>);
}
The concept of variadic templates is quite confusing to me and I want to make it a bit more complex (well I think...).
Let us consider the following code:
template <typename T>
class base
{
template <typename... E>
virtual void variadic_method_here(E... args) = 0;
};
and an implementing class:
class derive : public base<some_object>
{
void variadic_method_here(concrete_args_here);
};
How do I do that?
I think if I were faced with this problem I'd use CRTP and overloads to solve the problem.
e.g.:
#include <iostream>
template <typename Impl>
class base {
public:
template <typename... E>
void foo(E... args) {
Impl::foo_real(args...);
}
};
class derived : public base<derived> {
public:
static void foo_real(double, double) {
std::cout << "Two doubles" << std::endl;
}
static void foo_real(char) {
std::cout << "Char" << std::endl;
}
};
int main() {
derived bar;
bar.foo(1.0,1.0);
bar.foo('h');
}
You can't have a templated virtual function.