I am trying to make a class that has conditional members as below (sample code to illustrate problem):
template<bool b>
struct conditional_members {};
template<>
struct conditional_members<true>
{ int m; };
template<typename T, bool b>
struct my_class : public conditional_members<b>
{
T n;
// constructor for case when b is false
my_class(T n) : n(n) {};
// constructor for case when b is true
my_class(T n, int m) : n(n), m(m) {};
};
I need to have two conditional constructors depending on the bool b but this does not compile. I tried specializing the constructors with bool value:
template<typename T>
my_class<T, true>::my_class(T n, int m) : n(n), m(m) {};
template<typename T>
my_class<T, false>::my_class(T n) : n(n) {};
but that doesn't compile either because partial function template specializations are not allowed.
Is there a way to achieve this?
The problem with
// constructor for case when b is true
my_class(T n, int m) : n(n), m(m) {};
is that a constructor's mem-initializer-list can name only virtual base classes, direct base classes, and direct non-static data members, but never an inherited member like m. This is because the member of a base class is initialized by the base class subobject constructor, so it can't be initialized again (though it could be assigned).
You can instead specify the base class initializer. With this example, conditional_members is an aggregate, so aggregate initialization will work:
// constructor for case when b is true
my_class(T n, int m) : n(n), conditional_members<b>{m} {};
Though with just that, you might get some strange side effects from the fact that my_class specializations always have the two constructors declared, even if it might be invalid to actually instantiate one constructor or the other.
Here's an SFINAE trick to make the constructors conditionally effectively invisible, depending on b:
#include <type_traits>
// Define conditional_members as before.
template<typename T, bool b>
class my_class : public conditional_members<b>
{
T n;
public:
// constructor for case when b is false
template <typename = std::enable_if_t<!b>>
my_class(T n) : n(n) {}
// constructor for case when b is true
template <typename = std::enable_if_t<b>>
my_class(T n, int m) : conditional_members<b>{m}, n(n) {}
};
As a preview, with C++20 constraints, you'll be able to write it this nice, simpler way instead:
template<typename T, bool b>
class my_class : public conditional_members<b>
{
T n;
public:
// constructor for case when b is false
my_class(T n) requires(!b) : n(n) {}
// constructor for case when b is true
my_class(T n, int m) requires(b) : conditional_members<b>{m}, n(n) {}
};
Related
Consider a class with constexpr non static member function.
template <int k> class A { A() {} };
template <> class B : public A <k> {
B() : A{} {}
constexpr int foo() const { return k+42; }
}
Is foo() really compile time with any object of B? What about constexpr members?
template <int k> class A { A() {} };
template <> class B : public A <k> {
B() : A{} {}
constexpr int foo_var = k+42;
}
Will accesses to foo_var be compile time substituted? Will B have foo_var in its object memory layout?
What about std::array<T,N>::size()??
I'm trying to build a templat-class A and call its default constructor via a special word "NONE.
consider I have:
template<class T>
class A {
public:
A():_val(0);
A(T val):_val(val);
private:
int _val;
}
and I want to be able to write
A<int> x = None;
which will call A();
I was thinking maybe I can use some sort of typedef, but I don't know how
You could provide a dummy type and a constructor that takes that type and does the equivalent of default constructing an instance. For example,
struct None_t {};
constexpr None_t None{}; // const None_t None = {}; in C++03
template<class T>
class A {
public:
A() : _val() {};
A(None_t) : A() {} // A(None_t) : _val() {} in C++03
A(T val) : _val(val) {}
private:
T _val;
};
int main()
{
A<int> x = None;
}
Note I changed _val to from int to T, since otherwise the template doesn't make much sense.
The usual way would be to create a tag class, in this case none_type and have a constexpr (or static const) model of it available.
struct none_type {};
constexpr auto none = none_type {};
template<class T>
class A {
public:
A():_val(0) {};
A(none_type) : A() {};
A(int val):_val(val) {};
private:
int _val;
};
int main()
{
A<int> a = none;
}
I am facing errors when trying to do something similar as described below. Is this possible using class templates in c++.
I want to pass locally declared objects of class B and C and propagate till class A using the D class which acts as common interface for B and C interacting with A.
template<typename T1, typename T2>
Class A
{
protected:
T1 _t1;
T2 _t2;
public:
A(T1 t1 , T2 t2) : _t1(t1), _t2(t2) {}
};
class B {// do something};
class C {// do something};
template<typename M, typename N>
class D : public A<M,N>
{
public:
D(M m, N n)
{
A(m,n);
}
};
int main()
{
B objB;
C objC;
D<B,C> objD(objB, objC);
return 0;
}
}
Aside from the syntax errors (e.g. Class instead of class and parenthesis in comments) you should explicitly call the base class' constructor with the arguments you intend to pass to it
template<typename M, typename N>
class D : public A<M,N>
{
public:
D(M m, N n) : A<M,N>(m,n)
{}
};
since A does not have a default constructor.
Example here
I got a simple CRTP template class that I've been playing with and I came up to a point that I need to have the same ctor but essentially do different things at the constructor initialization list.
I do have an alternative solution but I was wondering if what I wanted to do could be achieved in a better way.
A strip down version of the class is pasted below.
You can ignore the Eigen stuff its just a matrix library.
template<class ImplT, size_t N, bool SquareMatrix = false>
class Foo
{
template<bool Test, typename Then, typename Else>
using conditional_t = typename std::conditional<Test, Then, Else>::type;
// this is defined at compile time so no need to init it
using VecN = Eigen::Matrix<double, N, 1>;
// this is a dynamic matrix so dimensions need to be specified at runtime
using MatN = Eigen::MatrixXd;
using MatrixType = conditional_t<SquarePreCovariance, MatN, VecN>;
inline ImplT& impl() noexcept { return static_cast<ImplT&>(*this); }
inline const ImplT& impl() const noexcept { return static_cast<const ImplT&>(*this); }
public:
// if SquareMatrix == false
Foo()
: parameters3(Matrix(N, N))
{}
// if SquareMatrix == true
Foo()
: parameters2(Matrix(N, N)),
parameters3(Matrix(N, N)),
{}
// easy solution that covers all cases
Foo()
: parameters3(Matrix(N, N)),
{
if (SquareMatrix)
parameters2.resize(N,N);
}
private:
VecN parameters;
MatrixType parameters2;
MatN parameters3;
};
What about conditionally delegating constructors?
private:
// if SquareMatrix == false
Foo(std::false_type)
: parameters3(Matrix(N, N))
{}
// if SquareMatrix == true
Foo(std::true_type)
: parameters2(Matrix(N, N)),
parameters3(Matrix(N, N))
{}
public:
Foo() : Foo(std::integral_constant<bool, SquareMatrix>{}) {}
Constructors can be templated, so long as all template arguments can be deduced or have defaults.
Substitution failures for template arguments cause it to be skipped during overload resolution.
Care must be taken to make it clear that the two constructor versions are valid overloads, and an additional dummy template parameter can take care of that.
#include <utility>
#include <iostream>
template <bool B>
struct S {
template <bool B_ = B, typename = typename std::enable_if<!B_>::type>
S() { std::cout << "1" << std::endl; }
template <bool B_ = B, typename = typename std::enable_if<B_>::type, typename = void>
S() { std::cout << "2" << std::endl; }
};
int main() {
S<false> sf; // okay, prints 1
S<true> st; // okay, prints 2
}
I have a struct defined as follows:
struct A : public B, public C
{
A(const B& b) : B(b), C()
{}
template<typename... Args>
A(Args&&... args) : B(), C(std::forward<Args>(args)...)
{}
};
int main()
{
B b;
A sample1(b);
A sample2(3); // For example, B has a B(int) constructor.
}
And this doesn't work fine, because, A(b) tries use the second constructor (the non-constant reference is the preferred option, and the first constructor is a constant reference), but B hasn't any B(A&).
And moreover, I want to add a move constructor for B:
struct A : public B, public C
{
A(const B& b) : B(b), C()
{}
A(B&& b) : B(std::move(b)), C()
{}
template<typename... Args>
A(Args&&... args) : B(), C(std::forward<Args>(args)...)
{}
};
Now, the last step is to fusion the first two constructors:
struct A : public B, public C
{
template<typename fw_B>
A(fw_B&& b) : B(std::forward<fw_B>(b)), C()
{}
template<typename... Args>
A(Args&&... args) : B(), C(std::forward<Args>(args)...)
{}
};
Question: if the first version causes collision, the last version (my final purpose) its clear that it doesn't work also. How could I achieve this goal?
A possible solution would be use std::enable_if with std::is_convertible to only include the first constructor if the type of argument b is convertible to B:
template <
class fw_B,
class = typename std::enable_if<std::is_convertible<fw_B, B>::value, T>::type>
A(fw_B&& b)
For example:
#include <iostream>
#include <type_traits>
struct B
{
B() {}
B(int) {}
};
struct C {};
struct A : B, C
{
template <
class T,
class = typename std::enable_if<std::is_convertible<T, B>::value, T>::type>
A(T&& t) { std::cout << "A(T&&)\n"; }
template <class... TArgs>
A(TArgs&&... targs) { std::cout << "A(TArgs&&)\n"; }
};
int main()
{
B b;
A a1(b);
A a2(4);
A a3("hello");
return 0;
}
Output:
A(T&&)
A(T&&)
A(TArgs&&)
See demo at http://ideone.com/xJEjic .