How can I pack a template class? - c++

I have use a packed template class. According to this I should wrap it with #pragma pack as in this example:
#include <iostream>
#pragma pack(1)
template<typename X>
struct S {
int a;
X b;
};
#pragma pack()
int main()
{
std::cout << sizeof(S<char>) << "\n";
}
Using gcc-4.4.7 on my centOS6, the program output 8, which means pack(1) didn't work. Then I tried to change main() to:
int main()
{
std::cout << sizeof(S<char>) << "\n";
#pragma pack(1)
std::cout << sizeof(S<char>) << "\n";
#pragma pack()
}
Surprisingly it still didn't work. If I comment out the first line in main() then it works. So my question is how to use pack on a template class instantiation? Is there anyway to use both packed and unpacked template class in the same program?
Update: If I use gcc-5.2.1, then it output 5 correctly. Also for the following program, I get opposite results (5 with gcc-4.4.7 and 8 with 5.2.1):
template<typename X>
struct S {
int a;
X b;
};
int main()
{
#pragma pack(1)
std::cout << sizeof(S<char>) << "\n";
#pragma pack()
}
Why do gcc-4.4.7 and 5.2.1 behave differently? Which one is correct? Is there anyway to get consistent result with different versions of gcc?

It works for me
#include <iostream>
#pragma pack(1)
namespace Packed
{
template<typename X>
struct S {
int a;
X b;
};
template struct S<char>;
}
#pragma pack()
namespace NotPacked
{
template<typename X>
struct S {
int a;
X b;
};
template struct S<char>;
}
int main()
{
std::cout << sizeof(Packed::S<char>) << "\n";
std::cout << sizeof(NotPacked::S<char>) << "\n";
}
You can put definition of S to header (but without #pragma once) and avoid code duplication:
#pragma pack(1)
namespace Packed
{
#include "S.h"
}
#pragma pack()
namespace NotPacked
{
#include "S.h"
}

Related

Simple Class and Header in Separate File Won't Work

I'm currently learning c++ for a week and here's my problem:
run.cpp
#include <iostream>
#include "Abc.h"
int main(){
int a;
std::cout << "Enter a : ";
std::cin >> a;
// Object Initialization
Abc AbcObj();
}
the header, Abc.h :
#ifndef ABC_H
#define ABC_H
class Abc
{
public:
Abc();
protected:
private:
};
#endif // ABC_H
and finally my cpp file for implementation, Abc.cpp:
#include "Abc.h"
#include <iostream>
Abc::Abc()
{
std::cout << std::endl << "Object created ";
}
Why don't I get output on my console? I'm expecting "object created" should be on the console. These files are in the same directory.
You error doesn't come up because you've used different files, so I have used one in this example
struct Foo
{
int a;
Foo()
{
std::cout << "Constructor called!";
}
};
int main()
{
Foo obj();
}
Why don't you see the message? You can read this thread
The problem here is, Foo obj() is taken as a function declaration. To fix this you need to remove the ()
int main()
{
Foo obj;
}
Constructor called!

Weird issue with external constants in constructor of template classes

I have the following three source files:
main.cc:
#include "constants.h"
#include <cstdlib>
#include <iostream>
template <std::size_t n> class Foo {
public:
static const double bar;
Foo();
};
template <std::size_t n> const double Foo<n>::bar = 4*pi;
template <std::size_t n> Foo<n>::Foo() { std::cout << "ctor: " << bar << std::endl; }
const Foo<42> baz;
int main(void)
{
std::cout << "main(): " << Foo<42>::bar << std::endl;
std::cout << "main(): " << baz.bar << std::endl;
return 0;
}
constants.cc:
#include "constants.h"
const double pi = 3.1415;
constants.h:
#ifndef CONSTANTS_H
#define CONSTANTS_H
extern const double pi;
#endif
and when I compile and link everything and run the executable I get:
ctor: 0
main(): 12.566
main(): 12.566
What gives? How comes the constructor of Foo<42> can't see the correct value of pi? This seems to only happen if Foo is a template, and only if pi is defined in a different file.
For what it's worth I'm using g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0. All of --std={c++,gnu++}{98,03,11,14,17} give the same results.
TIA for your answers.

Nifty counter in precompiled header does not work

To fix a problem caused by the static (de-)initialization order fiasco I tried to use the Nifty Counter idiom aka Schwartz Counter. I noticed, however, that it does not work if the header file containing the static initializer is included inside Visual Studio's precompiled header. In such a case I see in the debugger, that the constructor of the static initializer is called after the constructor of the other static object.
If I declare an additional static initializer right after #include "stdafx.h" or edit the precompiled header to not contain the declaration it works as expected.
Any ideas what might cause this?
EDIT
I was finally able to reproduce this problem in a new dummy project:
Foo.cpp
#include "stdafx.h"
#include "Foo.h"
#include <cassert>
#include <iostream>
#ifdef NIFTY
static int SchwartzCounter; // zero initialized at load time
static typename std::aligned_storage<sizeof(Foo), alignof (Foo)>::type foo_buf;
Foo& foo = reinterpret_cast<Foo&>(foo_buf);
#else
Foo foo;
#endif
Foo::Foo()
{
std::cout << __func__ << std::endl;
}
Foo::~Foo()
{
std::cout << __func__ << std::endl;
}
void Foo::doSomething()
{
std::cout << __func__ << std::endl;
assert(x == 42);
}
#ifdef NIFTY
FooInitializer::FooInitializer()
{
std::cout << __func__ << std::endl;
if (SchwartzCounter++ == 0)
{
new (&foo) Foo();
}
}
FooInitializer::~FooInitializer()
{
std::cout << __func__ << std::endl;
if (--SchwartzCounter == 0)
{
(&foo)->~Foo();
}
}
#endif
Foo.h
#pragma once
class Foo
{
public:
Foo();
~Foo();
void doSomething();
private:
int x = 42;
};
#ifdef NIFTY
extern Foo& foo;
static struct FooInitializer {
FooInitializer();
~FooInitializer();
} fooInitializer;
#else
extern Foo foo;
#endif
Bar.cpp
#include "stdafx.h"
#include "Foo.h"
#include "Bar.h"
#include <cassert>
#include <iostream>
#ifdef NIFTY
static int SchwartzCounter; // zero initialized at load time
static typename std::aligned_storage<sizeof(Bar), alignof (Bar)>::type bar_buf;
Bar& bar = reinterpret_cast<Bar&>(bar_buf);
#else
Bar bar;
#endif
Bar::Bar()
{
std::cout << __func__ << std::endl;
foo.doSomething();
}
Bar::~Bar()
{
std::cout << __func__ << std::endl;
}
void Bar::doSomething()
{
std::cout << __func__ << std::endl;
assert(x == 42);
}
#ifdef NIFTY
BarInitializer::BarInitializer()
{
std::cout << __func__ << std::endl;
if (SchwartzCounter++ == 0)
{
new (&bar) Bar();
}
}
BarInitializer::~BarInitializer()
{
std::cout << __func__ << std::endl;
if (--SchwartzCounter == 0)
{
(&bar)->~Bar();
}
}
#endif
Bar.h
#pragma once
class Bar
{
public:
Bar();
~Bar();
void doSomething();
private:
int x = 42;
};
#ifdef NIFTY
extern Bar& bar;
static struct BarInitializer {
BarInitializer();
~BarInitializer();
} barInitializer;
#else
extern Bar bar;
#endif
stdafx.h
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
// If the following define is commented out, the nifty counter idiom is not used
#define NIFTY
// If the following include is commented out while the nifty counter idiom is used, the initialization order is correct
#include "Foo.h"

CPP Code Concerning Classes is Showing Error

I wrote a pretty simple code for learning the concept of constructors.
I made a Project file in Dev-C++ 5.11, which uses the compiler TDM_GCC 4.9.2 32-bit Release.
Following is the code containing the main function:
#include <iostream>
#include "Classy1.h"
using namespace std;
int main()
{
Classy1 ao(3,4);
ao.printy();
return 0;
}
Here is the header file containing the class Classy1:
#ifndef CLASSY1_H
#define CLASSY1_H
class Classy1
{
private:
int v1;
int v2;
public:
Classy1(int a,int b);
void printy();
};
#endif
And here is the cpp file containing the constructor and the printy function:
#include "Classy1.h"
#include <iostream>
using namespace std;
Classy1::Classy1(int a,int b)
: v1(a), v2(b)
{
}
Classy1::printy()
{
cout << v1 << " " << v2;
}
Now, the compiler is showing an error on compilation:
You forgot to add a return type for the implementation of printy(). It should be:
void Classy1::printy()
{
cout << v1 << " " << v2;
}

Incomplete declaration of a partially specialized template

I am trying to partially specialize the std::hash struct for my own class TestHandle, and this class has its implementation split up using the opaque pointer idiom. So I am trying to provide the impl class with its own std::hash specialization. But I am running into templating problems.
Could someone help me understand why this is happening? I have attached all the necessary code below.
TestHandle.h
#pragma once
#include <memory>
class TestHandle {
public:
TestHandle();
void print();
class Impl;
std::unique_ptr<Impl> implementation;
};
TestHandle.cpp
#include "TestHandle.h"
#include "Impl.h"
#include <iostream>
using std::cout;
using std::endl;
TestHandle::TestHandle() : implementation{new TestHandle::Impl} { }
void TestHandle::print() {
this->implementation->print();
cout << "Hash of this->implementation is "
<< std::hash<TestHandle::Impl>()(*this->implementation) << endl;
}
Impl.h
#pragma once
#include "TestHandle.h"
#include <functional>
class TestHandle::Impl {
public:
void print();
int inner_integer;
};
namespace std {
template <> struct std::hash<TestHandle::Impl>;
}
Impl.cpp
#include "TestHandle.h"
#include "Impl.h"
#include <iostream>
using std::cout;
using std::endl;
#include <functional>
namespace std {
template <> struct hash <TestHandle::Impl> {
size_t operator() (const TestHandle::Impl& implementation) {
return std::hash<int>()(implementation.inner_integer);
}
};
}
void TestHandle::Impl::print() {
cout << "Printing from impl" << endl;
}
I am compiling with the following command
g++ -std=c++14 -c Impl.cpp TestHandle.cpp
and am getting the following error
TestHandle.cpp:11:12: error: invalid use of incomplete type 'std::hash<TestHandle::Impl>'
<< std::hash<TestHandle::Impl>()(*this->implementation) << endl;
template <> struct std::hash<TestHandle::Impl>;
Just forward declares the specialisation. It doesn't have to implement all the method (or any) of the original template. The compiler has no idea about the operator().
You will need to define the struct (in place of just the declaration);
template <> struct hash <TestHandle::Impl> {
size_t operator() (const TestHandle::Impl& implementation) const noexcept;
};
Side note: you will also need to provide the primary template (via inclusion) of <functional> (missing in the original listed code).