Zero-sized member variable in templated struct - c++

I have a templated struct that has a variant with an extra float, like this:
template <bool HasFloat>
struct Foo {
std::vector<int> a;
float b; // Not needed if HasFloat is false
};
To save memory (yes it is significant) I'd like to omit that float if HasFloat is false. Since there is a lot of other stuff in the struct the best way would be something like this:
using B = typename std::conditional<HasFloat, float, ZeroSizedType>::type;
B b;
Except there is no such thing as a zero sized type in C++ as far as I can tell. The only exception seems to be "Flexible Array Members", so I could maybe do something like this:
using B = typename std::conditional<HasFloat, float, float[]>::type;
Except they are only supported in C99, not C++.
The standard solution to this seems to be to use inheritance, since base classes can be zero-sized, however my struct is also accessed by assembly and to make the assembly simpler it is better if the float b; is at the end of the struct rather than the beginning, and anyway that isn't guaranteed.
So this seems to leave template specialisation as the only option but my class is actually rather long and I'd like to avoid duplicating everything. Is there another solution that I'm missing?

One of my colleagues came up with a fairly nice solution. It does require copy & pasting the data members but at least I don't have to duplicate my methods.
template <bool HasFloat>
struct Foo {
struct State {
std::vector<int> a;
};
struct StateWithFloat {
std::vector<int> a;
float k;
};
using FooState = std::conditional_t<HasFloat, StateWithFloat, State>;
FooState state;
};
You could do:
struct StateWithFloat {
State state;
float k;
};
But then you have to add template functions to avoid the state.a vs state.state.a problem and copy & pasting seems easier at that point.
Also #aschepler pointed out that in C++20 you will be able to use [[no_unique_address]].

You can create a struct specializing for has float or not, and then use it in your struct forwarding the template parameter. Something like this:
template <bool HasFloat>
struct PerhapsFloat;
template <>
struct PerhapsFloat<true>
{
float b;
};
template <>
struct PerhapsFloat<false>
{
};
template <bool HasFloat>
struct Foo {
std::vector<int> a;
PerhapsFloat<HasFloat> b;
};
Here, you have a demo:
https://godbolt.org/z/7zPto9

Try to extract the specialization to a base/member class.
template <bool B>
struct Foo {};
template <>
struct Foo<true>
{
float f;
};
template <bool HasFloat>
class Bar
{
Foo<HasFloat> b;
};
class Empty {};
int main()
{
std::cout << sizeof(Bar<true>) << std::endl; // 4
std::cout << sizeof(Bar<false>) << std::endl; // 1
std::cout << sizeof(Empty) << std::endl; // 1
}

Related

Explicit specialization template member and typedef

Found a curious emergent architecture (it wasn't designed intentionally but was created over time by adding up features) in code base, which looks like this, if dumbed down:
#include <iostream>
// Base class
template <class T>
struct Base {
typedef T DataT;
void foo();
};
// Parameter classes
struct A { int a[2]; };
struct B { int a[3]; };
// In original code Base<> had a complex list of arguments
typedef Base<A> ContainerA;
typedef Base<B> ContainerB;
// what allows to use ContainerA? It's a type name or explicit specialization?
// Class parameters, e.g. T, are unusable in this context directly.
template<> void ContainerA::foo() {
std::cout << "ContainerA " << sizeof(DataT) << std::endl;
}
template<> void ContainerB::foo() {
std::cout << "ContainerB " << sizeof(DataT) << std::endl;
}
int main()
{
ContainerA a;
ContainerB b;
a.foo();
b.foo();
}
Essentially, with multiple derived classes and complex template argument list this use of typedef saves time to type code and makes specialization declarations more readable. But which part of standard says that a typedef can be used in such way?
Code had partial support of C++11, no using = type declarations allowed.

C++ nested templates structs

So i have problem with code like this:
I have struct like this
template <int N>
struct Inner
{
enum
{
val = 2*N
};
};
And i want to achive sth like this:
int v = Outer<Inner<4>>::val;
int b = Outer<false>::val;
cout<< v <<endl;
cout<< b <<endl;
My goal is to created "Outer" struct which takes bool or Inner<int N> and set Outer::val to Inner::val or bool
So i have created sth like this (not working):
template <bool B>
struct Outer
{
enum
{
val = B
};
};
template <Inner<int> I>
struct Outer
{
enum
{
val = I::val
};
};
Whats wrong with this and how to fix that?
(I have seen some similar questions, but still can't apply this to my problem)
There are some problems in your code.
First of all: you define two different Outer structs
template <bool B>
struct Outer
{ /* ... */ };
template <Inner<int> I>
struct Outer
{ /* ... */ };
And you can't.
If you want, you can declare an Outer struct and two specializations, but you have to decide what type of template argument Outer has to receive.
Because, looking at your desiderata,
int v = Outer<Inner<4>>::val;
int b = Outer<false>::val;
you want pass to it a type in one case (Inner<4>) and a value in the other case. And you can't.
You have to decide if Outer receive a type or a value. Before C++17, if receive a value, you have to decide the type of the value; starting from C++17, you can declare Outer as receiving a value of a generic type (auto as type of the value).
Problem: a value of Inner<int> can't be a template parameter (but see also the Michael Kenzel's answer, that show a possible C++20 solution based on template values arguments).
So the only solution I see (before C++20) is declare Outer as receiving a type
template <typename>
struct Outer;
Then you can define a Outer specialization for Inner types
template <int N>
struct Outer<Inner<N>>
{ enum { val = Inner<N>::val }; }; // or simply enum { val = N };
For bool values, you have to wrap they in a class; I suggest (starting from C++11) the use of the standard class std::integral_constant and the definition of the following Outer specialization
template <bool B>
struct Outer<std::integral_constant<bool, B>>
{ enum { val = B }; };
The use is as follows
int v = Outer<Inner<4>>::val;
int b = Outer<std::integral_constant<bool, false>>::val;
std::cout << v << std::endl;
std::cout << b << std::endl;
You can also use std::false_type defining b
int b = Outer<std::false_type>::val;
and, starting from C++17, also std::bool_constant (a shorthand for std::integral_constant for bool values)
int b = Outer<std::bool_constant<false>>::val;
A template parameter can be either a type, a value (non-type), or a template [temp.param]. What you're trying to achieve would require your template Outer to have a parameter that can be either a type or a value. Unfortunately, this is not possible.
What you could do is wrap your bool value in a type:
template <bool b>
struct InnerBoolean
{
static constexpr bool val = b;
};
and then have one common definition for Outer
template <typename T>
struct Outer
{
enum
{
value = T::val
};
};
and then use Outer<Inner<4>> and Outer<InnerBoolean<False>>.
Rather than write your own wrapper, if you rename val to value, you can use the wrappers that the standard library provides in std::bool_constant and std::true_type and std::false_type.
While up to C++17, a non-type template parameter cannot be of class type [temp.param]/4, C++20 will lift this restriction and allow template parameters of any literal type. Thus, as long as Inner can be a literal type, you will be able to just pass a value of type Inner directly and use an auto template parameter:
struct Inner
{
int N;
constexpr Inner(int N) : N(N) {}
constexpr operator int() const { return 2*N; }
};
template <auto val>
struct Outer
{
enum
{
value = val
};
};
auto a = Outer<Inner(4)>::value;
auto c = Outer<false>::value;

set public/private on template function for some certain template parameter

Is it possible to make a certain template function have 2 accessibility level for some certain template parameter? (via splitting into 2 functions?)
class B{
enum ENU{
T0,T1,T2
}
template<ENU T=T0> someType f(){ ... } //want T1,T2 = public, T0 = private
};
Current usage (the solution should not change it):-
B b;
int aa=b.f<T0>(); //should fail
std::string bb=b.f<T1>();// should ok
Edit: B has a lot of functions like this.
Here is the full code (just in case someone want to edit or use) https://ideone.com/ryNCml.
I doubt what you are trying to do is possible, as specializing functions on a value ain't allowed in C++.
Though if you don't need enumerations, you could write something similar:
class B {
public:
struct T0{};
struct T1{};
struct T2{};
template<typename T> void f(T, ...) {
static_assert(std::is_same_v<T, T1> || std::is_same_v<T, T2>);
}
private:
void f(T0, ...) {}
};
int main(int argc, char **argv) {
B b{};
b.f(T1{}); // Should compile
b.f(T0{}); // Should not compile
}
If you would use the same function implementation, you can either forward this to a common method, or simply put T0 private.
Alternatively, you could make use of a proxy object which could convert the value, though I'm not sure if this is standard C++ of an extension of the compiler I'm familiar with:
class B {
public:
enum class T { //< Strong typed!
T0,
T1,
T2
}
template <T t>
struct TWrapper {};
template <T ActualT>
void f(..., TWrapper<ActualT> tw = TWrapper<ActualT>{});
private:
template <>
struct TWrapper<T0> {};
}
As far as I can understand, you want to forbid the use of T0 as a template parameter while invoking member method f.
To do that, you can use either std::enable_if or a static_assert.
It follows a minimal, working example:
#include<type_traits>
class B {
public:
enum ENU { T0,T1,T2 };
template<ENU T>
std::enable_if_t<(T==T1||T==T2),int>
f() { return 42; }
template<ENU T>
int g(){
static_assert(T==T1||T==T2, "not allowed");
return 42;
}
};
int main() {
B b;
b.f<B::T1>();
// It doesn't work
//b.f<B::T0>();
b.g<B::T1>();
// It doesn't work
//b.g<B::T0>();
}
Given you want to support only a finite set of template arguments, I would write three functions which are not template functions, and give them the right visibility. Then make them delegate to a private template function which does the work. This would look like:
class B{
public:
enum ENU{
T0,T1,T2
}
private:
template<ENU T=T0> int f(){
std::cout<<"In enum "<<T<<std::endl;
return 0;
}
protected:
someType fT0() { return f<T0>(); }
public:
someType fT1() { return f<T1>(); }
someType fT2() { return f<T2>(); }
};
Contrary to your requirements, the usage changes - but this is often the simplest approach:
B b;
int aa=b.fT0(); // fails
int bb=b.fT1();// ok
Alternatively, you can make the template be public, but give it a dummy argument (with a default), and make the type of the dummy argument depend on the template parameter (via traits). If the type of the dummy is a private class, the template will only be callable by a member.
template <ENU T>
struct protection_traits;
class B{
friend class protection_traits<T0>; // So it has access to Protected.
protected:
struct Protected{};
public:
struct Public{};
enum ENU{
T0,T1,T2
}
template<ENU T=T0> int f( typename protection_traits<T>::type = {})
{ std::cout<<"In enum "<<T<<std::endl; }
};
template <ENU T>
struct protection_traits
{
typedef B::Public type; // Default to public
};
template<>
struct protection_traits<T0>
{
typedef B::Protected type; // But T0 uses Protected
};
Usage:
B b;
int aa=b.f<T0>(); // fails (no access to B::Protected)
int bb=b.f<T1>(); // ok
Note: This latter solution hasn't been fed to a compiler. There will be typos.

c++ std::enable_if

I am quite new to std::enable_if and wondering how to use it.
I have a template class:
template<int a, int b>
class foo {
}
Now I only want to instantiate it when a + b equals to 10.
Could I make this possible using std::enable_if?
The second question:
If I have a member in class foo
template<int a, int b>
class foo {
int c;
}
I only want to have c when
a = 5.
How do I do that using std::enable_if?
Is this one the correct case to use std::enable_if?
template<int a, int b, typename T = typename std::enable_if<a + b == 10>::type>
class foo {
};
This should do the job; just make sure you never explicitly provide the third template parameter when instantiating the template.
As others mentioned, static_assert is a much better fit.
I guess you can use static_assert better to enforce that constraint instead of enable_if
template<int a, int b>
class foo {
static_assert(a+b==10, "a+b is not 10");
};
int main()
{
foo<5,5> f; // will compile
foo<1,5> f; // will fail to compile with error: a+b is not 10
return 0;
}
enable_if is primarily used to conditionally remove functions and classes from overload resolution based on type traits and to provide separate function overloads and specializations for different type traits.
With C++20
You can achieve that simply by adding requires to the template:
template<int a, int b> requires (a + b == 10)
struct foo {
int c;
};
int main() {
foo<3, 7> ok;
// foo<3, 8> doesnt_compile;
}
The requires clause gets a constant expression that evaluates to true or false deciding thus whether to consider this as a proper match, if the requires clause is true, or ignore it otherwise.
Code: https://godbolt.org/z/yHh4Et
Simple, just don't use enable_if
template<bool Ten>
struct Base
{
int c;
};
template<>
struct Base<false>
{ };
template<int a, int b>
struct foo : Base<a+b == 10>
{
};

C++ template specialization problem

I need a C++ template that, given a type and an object of that type, it can make a decision based on whether the type is an integer or not, while being able to access the actual objects. I tried this
template <typename T, T &N>
struct C {
enum { Value = 0 };
};
template <int &N>
struct C<int, N> {
enum { Value = N };
};
but it doesn't work. Is there any way I can achieve something similar?
Edit
What I was trying to achieve was something like this, that would happen at compile time:
if (type is int) {
return IntWrapper<int_value>
else {
return type
}
You can actually pass pointers or references to objects in a template instantiation, like so:
struct X {
static const int Value = 5;
};
template <X *x>
struct C {
static const int Value = (*x).Value;
};
X x;
std::cout << C<&x>::Value << std::endl; // prints 5
but apparently all this accomplishes is to initialize the template by inferring x's type, and x also needs to be declared globally. No use for what I'm trying to do, which I think is not possible after all at compile time.
What you are attempting to do isn't valid C++ templating. You can't use arbitrary objects as template parameters, all you can use are types, integral literals and in certain specialised cases string literals.
Unless i misunderstand you, what you want is impossible. In your example you show an invalid use of a pointer template parameter.
template <X *x>
struct C {
static const int Value = (*x).Value;
};
That's not valid, since (*x).Value must be a constant expression for it to be able to initialize Value. Sure Value within class X would be fine as a constant expression when used as X::Value instead. But this time, it's not since it involves a pointer (references are equally invalid in constant expressions).
To sum up, you can't do this:
Magic<T, someT>::type
And expect ::type to be T if T isn't int, and IntWrapper<someT> otherwise, since T can only be an enumeration, integer, pointer or reference type. And in the latter two cases, you won't get at the "value" of anything pointed to by the pointer or referred to by the reference at compile time. If you are satisfied with that, it's easy to solve your problem and i'm not going to show you how (i suspect you already know how).
I think you have driven yourself into a situation where solving your problem has become impossible to do with the rules as given. Drive back some steps and show us the real problem you are trying to solve, when the matter still allows to solve things.
Perhaps a simple overloaded template method works in your case?
template<typename T>
void doSomething(const T& x)
{
// ...
}
void doSomething(int x)
{
// ...
}
Addition to the other posts: You don't need to use the enum {}-hack any more:
template<typename T, int val>
struct Test {
static const int Value = 0;
};
template <int val>
struct Test<int, val> {
static const int Value = val;
};
int main(int argc,char *argv[]) {
const int v = Test<int,1>::Value;
}
template <typename T> struct A
{
enum { Value = false };
};
template <> struct A<int>
{
enum { Value = true };
};
How about this then:
template <typename T> struct A
{
T value_;
A() : value() {}
enum { is_int = false };
};
template <> struct A<int>
{
int value_;
explicit A( int v ) : value_( v ) {}
enum { is_int = true };
};
I need a C++ template that, given a
type and an object of that type, it
can make a decision based on whether
the type is an integer or not, while
being able to access the actual
objects.
You can make decisions based on the type being an integer or not, the problem is it's impossible to declare a template with an object of any type. So the question on how to decide wether a type is an integer is moot.
Note that in all answers your original template is neatly changed to
template < typename T, int >
class C {};
instead of your
template< typename T, T >
class C {};
But while C<int, 5> is a perfectly valid declaration, this is not the case for an arbitrary type T, case in point C<float, 5.> will give a compiler error.
Can you post what you're trying to achieve exactly?
And for the record, if the second template argument is always an int, and you simply want to take its value if the type is an integer type, and 0 otherwhise, you can simply do:
#include <limits>
template< typename T, int N >
class C {
static const int Value = (std::numeric_limits<T>::is_integer) ? N : 0;
};
You can do it like this:
template<typename T, int val>
struct Test
{
enum {Value = 0};
};
template <int val>
struct Test<int, val>
{
enum {Value = val};
};
int main(int argc,char *argv[])
{
int v = Test<int,1>::Value;
}
simple fix to your code - loose the reference:
template <typename T, T N>
struct C {
enum { Value = 0 };
};
template <int N>
struct C<int, N> {
enum { Value = N };
};
using reference in a template argument is meaningless anyway because you're not actually passing the argument anywhere.
Check out Alexandrescu's Modern C++ Design. I believe chapter 2 has a correct example of what you want to do.
Template specialization can be achieved like this (code taken from www.cplusplus.com):
// template specialization
#include <iostream>
using namespace std;
// class template:
template <class T>
class mycontainer {
T element;
public:
mycontainer (T arg) {element=arg;}
T increase () {return ++element;}
};
// class template specialization:
template <>
class mycontainer <char> {
char element;
public:
mycontainer (char arg) {element=arg;}
char uppercase ()
{
if ((element>='a')&&(element<='z'))
element+='A'-'a';
return element;
}
};
int main () {
mycontainer<int> myint (7);
mycontainer<char> mychar ('j');
cout << myint.increase() << endl;
cout << mychar.uppercase() << endl;
return 0;
}
In your case you would have to replace the char by what you want in the class template specialization. Now, I am not really sure what you are trying to accomplish but I hope the example above is a good indicator to how you can do some template specialization.
What I was trying to achieve was something like this, that would happen at compile time:
if (type is int) {
return IntWrapper<int_value>
else {
return type
}
I'm not sure why you aren't using IntWrapper to begin with. Where does the need come from to wrap a compile-time integer constant into an IntWrapper, if it is int?
Otherwise it looks a bit that you are trying to instantiate templates with data that is only available at run-time.