All solutions compare the size to char

The third is simplest and is applicable to any class or structure besides basic types. Other two are more complex but interesting on their own nevertheless.

Code:
// if you prefere size in bytes
#define BYTE_SIZE 8 

// if you prefere size in bits
// #define BYTE_SIZE 1 

int sizeChar()
{
	static int c = sizeChar();
	if (c != 0) return c; // call it only first time

	c = 1;
	char t = (char)1;
	while ( t <<= 1 ) c++;
	c /= BYTE_SIZE;

	return c;

}

template<typename T>
int my_sizeof_3()
{
	int c = sizeChar();

	T t[2];
	char* a[2];
	
	a[0] = (char*)&t[0]; // convert to char
	a[1] = (char*)&t[1]; // convert to char at the second element
	
	int n = 0;

	while (a[1] != a[0]) // go back until first and second match
	{
		a[1]--; 
		n++;
	}

	return n*c;
}
The first solution uses two elements one after another and then changes slowly the entire portion of memory to see when the first element does not change any more. It means we have started to change the bytes in the second element and there we can calculate the size.
The second solution needs assumed maximum expected size and then it shrinks and changes memory byte by byte and examine at which moment our element would show any change. At that moment we are inside the memory that is occupied by our element and we can calculate the size.

sizeChar is there only if we really want to have the size of char calculated first

Both functions can give size in bytes or size in bits depending on BYTE_SIZE definition.


For the size of larger structure like class and struct we need the solution number 3

Code:
// if you prefere size in bytes
#define BYTE_SIZE 8 

// if you prefere size in bits
// #define BYTE_SIZE 1 

int sizeChar()
{
	static int c = sizeChar();
	if (c != 0) return c; // call it only first time

	c = 1;
	char t = (char)1;
	while ( t <<= 1 ) c++;
	c /= BYTE_SIZE;

	return c;

}

template<typename T>
int my_sizeof_1()
{
	int c = sizeChar();

	T e[2];

	e[0] = 0;
	e[1] = 0;

	char* str = (char*)e;

	int n = 0;
	T p;

	do
	{
		p = e[0];
		str[n++] = 1;
	}
	while(e[0] != p);

	return (n-1)*c;
}

#define MAX_EXPECTED_SIZE 20

template<typename T>
int my_sizeof_2(int max_size = MAX_EXPECTED_SIZE)
{
	int c = sizeChar();

	char* e;

	while(1)
	{
		e = new char[max_size];
		
		for(int i = 0; i < max_size-1; i++ )
			e[i] = 0;

		e[max_size-1] = 1; // set only last element to 1

		T* y = (T*)e; 	// convert to see if type value
// would remain 0

		if(*y != 0) 
		{
			delete e;
			break;
		}

		delete [] e;
		
		max_size--;
	}

	return max_size*c;
}
Usage

Code:
struct Sample
{
	int a,b,c,d,e,f,g;
};

	int size = my_sizeof_1<int>();
	size = my_sizeof_1<double>();
	size = my_sizeof_1<char>();
	size = my_sizeof_1<long int>();

	size = my_sizeof_2<int>();
	size = my_sizeof_2<double>();
	size = my_sizeof_2<char>();
	size = my_sizeof_2<long int>();

	size = my_sizeof_3<int>();
	size = my_sizeof_3<double>();
	size = my_sizeof_3<char>();
	size = my_sizeof_3<long int>();
	size = my_sizeof_3<Sample>();