Templates - Help

Hi there, I have a question about templates and I have been banging my head against a wall with this for 2 days... I think I have tried and googled everything but I cannot understand why I can't do it.

My problem simplified is a template class that looks like this....

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
template<class T>
Class Foo
{
  template<typename sometype>
  Foo(sometype type) : sze(sizeof(type))
  {
     // Happy compiler here

     X<sizeof(type)>::SomeStaticMethod();
     // Or
     X<sizeof(type)> x;
     x.SomeClassMethod();
  }

  void Bar()
  {
    // Unhappy compiler here
    X<sze>:: // Some callable method through specialization of class X
  }

  const int sze;
};


Now, in class foo I pass a type into the constructor and I can take it's size using the sizeof operator, I can pass the result from the sizeof operator to a specialized template and the compiler is happy, shown in the example above. But, what I can't do and what I want to do is be able to create the specialized class in member Bar. I have tried declaring a const class member and assigning in the constructor ( which should work becuase the value of the const member is derived from the sizeof operator and therefore known at compile time. But of course the compiler complains about not having a compile time constant expression, which it actually has.

Can anyone help me solve this or at least explain why the compiler will allow it in the constructor but not in the method Bar.

By the way I can't pass in the type as a class template parameter, that would make it easy! :)

I would appreciate anyone that can help me.

best regards
Last edited on
You have to use polymorphism here - look up how boost::any works. Since the constructor is the only place with compile-time access to the type, it needs to be where the derived class is instantiated, and the derived class has your Bar member function in it.
Yes, although I was hoping to avoid anything virtual and go for a template meta-programming solution, i've tried quite a few things but can't get the result I want.

The problem is simply that class members are runtime initialized so that is why the template can't deduce a compile time constant, however all the information for the compiler to do what I ask is available seeing as the sizeof operator does it's thing at compile time.

When the template is used to create the class the compiler should be able to deduce the values, assuming an outside-in compilation of course.
Last edited on
Is there an actual reason you are templating the constructor instead of the entire class?
Yes, if I were to pass the type as a class template type then I wouldn't have a generic class capable of compile time dispatch. Even looking at c++11 features such as constexpr are not of any help. In all truth I can accomplish this in a different way but I'm quite enjoying the challenge of this. It may not be possible at all however given the way in which I understand templates are used to create classes I fail to see why. If you consider the following order of events...

Compiler examines Template class
Substitution of template parameters for actual types
Constructor has template parameters so it is "run" for the want of a better word at compile time.
Constructor arguments and code within deduced at compile time.

So this being true there is no reason ( that I can think of ) that any value deduced in a templated constructor would not be available to the rest of the class, the only problem so far as I can see is that there simply isn't a mechanism to tell the compiler to basically "copy and paste " this value into all instances where it is defined as a symbol.

Like I say it seems as though it should be possible, but apparently isn't, with the knowledge I have anyway.
Last edited on
> if I were to pass the type as a class template type
> then I wouldn't have a generic class capable of compile time dispatch.

Write a helper forwarding function to deduce the type and perform compile time dispatch.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>

template < std::size_t SZ > struct X
{ static constexpr const char* sfn() { return "\101 X<non-specialised>::sfn" ; } };

template <> struct X< sizeof(int) >
{ static constexpr const char* sfn() { return "\102 X< specialised: sizeof(int) >::sfn" ; } };

template < typename T, std::size_t SZ = sizeof(T) > struct foo
{
    template < typename U > constexpr foo( U&& ) { /* ... */ }

    constexpr const char* bar() const { return X<SZ>::sfn() ; }

    std::size_t sz = SZ ;
};

template < typename T, typename U > constexpr auto make_foo( U&& u )
{ return foo< T, sizeof(U) >{ std::forward<U>(u) } ; }

int main()
{
    constexpr auto foo_dbl_dbl = make_foo<double>( 45.7 ) ;
    std::cout << foo_dbl_dbl.bar() << '\n' ;

    constexpr auto foo_dbl_int = make_foo<double>(45) ;
    std::cout << foo_dbl_int.bar() << '\n' ;
    
    static_assert( make_foo< const char* >( 45.7 ).bar()[0] == 0101, "unexpected result" ) ;
    static_assert( make_foo< const char* >( 45 ).bar()[0] == 0102, "unexpected result" ) ;
}

http://coliru.stacked-crooked.com/a/ceb0a8ca2b747fce
http://rextester.com/NAQQL91814
Last edited on
Some pretty code there but I can't use i for my purpose because of the daft way that constexpr works. Effectively all that constexpr does is simplify template meta-programming. In the snipet posted above class Foo cannot be a class member which is what I want class Foo to be.

1
2
3
4
5
6
7
8
SomeClass
{
///{...}

private:

Foo foo;
};


Now the way I see it is this, it should be absolutely possible to declare a constexpr class member in a template class that is initialized in a constructor as part of the member initialization list as a result of a compile time constant expression i.e sizeof

The fact that I can't tells me that C++ isn't truly object oriented as if it were the constructor would have knowledge of all of it's members and be able to initialize them properly.

The benefits to the language of introducing what I have described reach far and wide, effectively you would be able to create compile time #defines, can you imagine how useful that would be. It's not a massive deal for compiler vendors to implement either.

Bringing in this mechanism would reduce application size, and make much MUCH faster code, conditional removal of methods and even classes, the list is endless.

It's a shame, it's not there.

However thank you to all that relied and tried to help out.
Last edited on
Your example doesn't compile, it's better to post a compilable one, otherwise it's not easy to understand your real problem.
However, I think you could solve using sze as template parameter (with default value) instead of member variable:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
template<class type, size_t sze = sizeof(type)>
class Foo
{
public:
	Foo()
	{
		// Happy compiler here

		X<sizeof(type)>::SomeStaticMethod();
		// Or
		X<sizeof(type)> x;
		x.SomeClassMethod();
	}

	void Bar()
	{
		// Unhappy compiler here
		X<sze>::SomeStaticMethod(); // Some callable method through specialization of class X
	}
};


But, obviously you could use sizeof(type) instead of sze, like in the constructor, so sze is useless in this case.
If you have a different issue, you should post a compilable code.
> In the snipet posted above class Foo cannot be a class member which is what I want class Foo to be.
> it should be absolutely possible to declare a constexpr class member in a template class that is
> initialized in a constructor as part of the member initialization list
> as a result of a compile time constant expression i.e sizeof

The result of a compile time constant expression can be a template non-type argument; there is no real need for a non-static constexpr member object initialised via a templated constructor.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>

template < std::size_t SZ > struct X
{ static constexpr const char* sfn() { return "\101 X<non-specialised>::sfn" ; } };

template <> struct X< sizeof(int) >
{ static constexpr const char* sfn() { return "\102 X< specialised: sizeof(int) >::sfn" ; } };

template < typename T, std::size_t SZ > struct foo
{
    template < typename U > constexpr foo( U&& ) { /* ... */ }

    constexpr const char* bar() const { return X<SZ>::sfn() ; }

    std::size_t sz = SZ ;
};

template < typename T, std::size_t SZ > struct SomeClass
{
    template < typename U > constexpr SomeClass( U&& u ) : object( std::forward<U>(u) ) { /* ... */ }

    constexpr const char* bar() const { return object.bar() ; }

    private: foo<T,SZ> object ; // a constexpr member object

};

template < typename T, typename U > constexpr auto make_SomeClass( U&& u )
{ return SomeClass< T, sizeof(U) >{ std::forward<U>(u) } ; }

int main()
{
    constexpr auto SomeClass_dbl_dbl = make_SomeClass<double>( 45.7 ) ;
    std::cout << SomeClass_dbl_dbl.bar() << '\n' ;

    constexpr auto SomeClass_dbl_int = make_SomeClass<double>(45) ;
    std::cout << SomeClass_dbl_int.bar() << '\n' ;

    static_assert( make_SomeClass< const char* >( 45.7 ).bar()[0] == 0101, "unexpected result" ) ;
    static_assert( make_SomeClass< const char* >( 45 ).bar()[0] == 0102, "unexpected result" ) ;
}
H i and thank you for all the replies, btw fcantoro I know my original post doesn't compile which is why I included the coments to demonstrate my intent :)

Ok, in the example it is not possible to have Foo declared as a member of a general class as it requires it to be declared as constexpr in order to call the constexpr constructor and in fact it is not possible at all. i.e you can't do this....

1
2
3
4
5
6
7
class SomeNonTemplateClass 
{
...

private:
Foo foo // not possible as a constexpr
};


Now you say that you don't really need a initializable constexpr member, but consider the following class...


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
template<typename T> // some common type known at the time of declaration
struct Foo
{

 Foo() = default;

 template<class ctype>
 Foo(ctype type) : cexpr(sizeof(type)) {}

Foo(const Foo&& foo) : cexpr(foo.cexpr)
{
}

template<class type>
static Foo<T> Get(type ty)
{
return std::forward<Foo<T>>(Foo<T>(type))
}
//....

void CallSomeCompileTimeMethod(void)
{
SomeSpecializedClass<cexpr>::SomeMethod // static in this example but not necessarily so.
}

constexpr std::size_t cexpr;

};// end Foo 



Now inside a general class....

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class SomeGeneralClass
{
....

SomeMemberMethod(void)
{
foo = Foo<KnownType>::Get(Only now do we know this type);
foo.CallSomeCompileTimeMethod();
}

private:

Foo<KnownType> foo // default constructor called.
}


So as you can see from above if this were possible class Foo could be a generic dispatching class for any number of methods, in this case based on an objects size. In release mode the compiler would ( in the absence of any classes using virtual inheritance ) optimize away class Foo entirely and it would implicitly inline the method called by CallSomeCompileTimeMethod.

Yes, I know I have an uninitialized constexpr in class Foo, but this in and of itself is not a big issue, remember this happens at complile time so it could therefore follow SFINAE. Any code paths using an uninitialized constexpr cause the the path to be removed, or failing that a compile time error seeing as the sizeof operator is one of the very first to be evaluated; it has to be this way so the stack can be properly grown and unwound.

I apologise in advance for any mistakes in my examples, it's written from memory and only there to describe my intention.

Last edited on
Topic archived. No new replies allowed.