The following code contains an example template X
, where the data-member is unused, if the template is parametrized with other type than A
. But the sizes of the objects a
and b
are the same, even with -O3
, so the optimizer does not remove the unused data-member x2
.
#include <iostream>
#include <cstdint>
#include <type_traits>
struct A {};
struct B {};
template<typename T>
struct X {
int value() const {
if constexpr(std::is_same_v<T, A>) {
return x1 x2;
}
else {
return x1;
}
}
private:
int x1{0};
int x2{0};
};
int main() {
X<A> a;
X<B> b;
std::cout << sizeof(a) << '\n';
std::cout << sizeof(b) << '\n';
return a.value() b.value();
}
Now there are two questions:
- Is the optimizer not allowed (
as-if
-rule) to remove the unused data-member? Why? - How to achieve the goal: that the class
X<B>
does not contain the unused data-memberx2
?
There is a workaround with a base-class template and a specialisation for A
that contains the data-member x2
. But this solution is cumbersome. I wonder if there is a solution without using a base class?
Edit:
I don't think that using the sizeof()
operator prevents the optimization:
//#include <iostream>
#include <cstdint>
#include <type_traits>
struct A {};
struct B {};
template<typename T>
struct X {
int value() const {
if constexpr(std::is_same_v<T, A>) {
return x1 x2;
}
else {
return x1;
}
}
private:
int x1{0};
int x2{1};
};
X<A> a;
X<B> b;
int main() {
// std::cout << sizeof(a) << '\n';
// std::cout << sizeof(b) << '\n';
return a.value() b.value();
}
If you look a the assembly (e.g. compiler explorer) you see that the instances contain in both cases both data-members.
CodePudding user response:
Here is an ugly solution if x1 and x2 has the same type:
template<typename T>
struct X {
int value() const {
if constexpr(std::is_same_v<T, A>) {
return x1() x2();
}
else {
return x1();
}
}
int x1() const {
return x[0];
}
int x2() const {
return x[1];
}
private:
//int x1{0};
//int x2{0};
int x[1 std::is_same_v<T, A>] = {};
};
CodePudding user response:
You can move the data members to a base class, and inherit conditionally.
namespace detail {
struct XA {
int x1{0};
int x2{0};
};
struct XB {
int x1{0};
};
}
template<typename T>
struct X : private std::conditional_t<std::is_same_v<T, A>, detail::XA, detail::XB>{
int value() const {
if constexpr(std::is_same_v<T, A>) {
return x1 x2;
}
else {
return x1;
}
}
};