What is the type of T? - c++

In the code below:
template<typename T>
struct X {};
int main()
{
X<int()> x; // what is the type of T ?
}
What is the type of T? I saw something like this in the boost sources.

Consider the function int func(). It has a function type int(void). It can be implicitly converted to pointer type as the C++ Standard says in 4.3/1, but it this case there's no need in such conversion, so T has the function type int(void), not a pointer to it.

Here is what I did. Though the output of code below is implementation specific, many times it gives a good hint into the type of T that we are dealing with.
template<typename T>
struct X {
X(){
cout << typeid(T).name();
}
};
int main()
{
X<int()> x; // what is the type of T ?
cout << typeid(int()).name() << endl;
}
The output on VC++ is
int __cdecl(void)
int __cdecl(void)

The type of T is a function that takes no parameters and returns int, as in:
template<typename T>
struct X {};
int foo()
{
return 42;
}
int main()
{
X<int()> x; // what is the type of T ?
typedef int(foo_ptr)();
X<foo_ptr> x2;
return 0;
}
T in x and x2 are the same type.

Related

C++ template specifying type in the parameter

In a C++ template when you specify the type in the parameter (example below) does this imply that the type has to be an int or this a hint?
template<typename T=int>
class Square_
{
}
You specify a default type. This means you can omit the type when instantiating the template, in which case this default type is chosen. But when you manually specify a type, this one has precedence. Example:
Square_<double> sq1; // explicitly given
Square_<> sq2; // uses default: int
It's a default, same as for function arguments. So, you can use Square_<> to mean the same as Square_<int>, when you don't want to choose a different type to the default.
Eg, this:
#include <iostream>
#include <typeinfo>
void function(int i = 42)
{
std::cout << "function(" << i << ")\n";
}
template <typename T = int>
void function_template()
{
std::cout << "function_template<" << typeid(T).name() << ">\n";
}
int main() {
function();
function(56);
function_template<>();
function_template<double>();
}
gives me the output
function(42)
function(56)
function_template<i>
function_template<d>
(the printed names of the types int and double may be different on your system)
It means if you use empty <>, it is equivqlent to use
See the example below.
template<typename T=int>
class Square_
{
public:
Square_()
{
if (std::is_same<T, int>::value)
{
std::cout<<"I am an int"<<std::endl;
}
else
{
std::cout<<"I am not an int"<<std::endl;
}
}
};
int main() {
Square_<> s1;
Square_<int> s2;
Square_<double> s2;
// your code goes here
return 0;
}
Output:
I am an int
I am an int
I am not an int

c++ template for constant data holder class

I am trying to design a class which all its data is constant and know at compile time. I could just create this by manually typing it all but I want to use a template so that I don't have to rewrite almost the same code many times.
I was thinking templates are the way to do this e.g
template<class T> class A { ... }
A<float>
A<MyObject>
A<int>
But then I wasn't sure how I could get the constant data that I know into this object. I could do it at run-time with a member function which does a switch statement on the type or something similar but I ideally want it to effectively be a dumb data holder for me to use.
So in the case of A<float> I would have this:
// member function
int getSize() {
return 4;
}
Instead of (pseudo code)
// member function
int getSize() {
if (type == float) {
return 4;
} else if ...
}
I'm wondering if there is a known way to do this? I don't have any experience with constexpr, could that be the key to this?
edit: To clarify: I want member functions which always return the same result based on the templated type/class. For example, A would always return 4 from getSize() and 1 from getSomethingElse() and 6.2 from getAnotherThing(). Where as A would return 8 from getSize() and 2 from getSomethingElse() and 8.4 from getAnotherThing().
You can have this template
template <int size_, int foo_, int bar_>
struct MyConstData {
static const int size = size_; // etc
};
Then specialize your template:
template <class T> class A;
template <> class A<float> : MyConstData<13,42,-1> {};
template <> class A<double> : MyConstData<0,0,42> {};
You can specialize particular functions within a class, and given your description of things, I suspect that's what you want. Here is an example of how this works:
#include <iostream>
#include <string>
template <class T>
class A {
public:
int MyConstantFunction() const { // Default implementation
return 0;
}
};
template <>
int A<int>::MyConstantFunction() const
{
return 3;
}
template <>
int A<float>::MyConstantFunction() const
{
return 5; // If you examine the world, you'll find that 5's are everywhere.
}
template <>
int A<double>::MyConstantFunction() const
{
return -5;
}
int main(int, char *[])
{
using ::std::cout;
A<int> aint;
A<float> afloat;
A<long> along;
cout << "aint.MyConstantFunction() == " << aint.MyConstantFunction() << '\n';
cout << "afloat.MyConstantFunction() == "
<< afloat.MyConstantFunction() << '\n';
cout << "along.MyConstantFunction() == "
<< along.MyConstantFunction() << '\n';
return 0;
}
Notice how along just used the default implementation from the class declaration. And this highlights a danger here. If the translation unit using your specialization for a given type hasn't seen that specialization, it won't use it, and that may cause all kinds of interesting problems. Make sure this happens.
The other option is to not provide a default implementation at all, and so you get an instantiation error.
My gut feeling is that you are doing something that is pointless and a poor design. But, since I don't know the full context I can't say that for sure. If you insist on doing this, here's how.
If you want to implement different things depending on the type, you could try this:
template <class T>
class Foo {
T data;
string toString() {
return myGeneralToString(data);
}
};
template <>
class Foo<string> {
string data;
string toString() {
return "Already a string: " + data;
}
};
If you just want templated constants, I'd try this:
template <int a, int b>
class Calc {
public:
static constexpr int SUM = a + b;
};
int main()
{
std::cout << Calc<3, 5>::SUM << std::endl;
return 0;
}
Edit: as pointed out by Omnifarious C++14 has templated constants without templating the class itself. So you could simplify the example to:
class Calc {
public:
template <int a, int b>
static constexpr int SUM = a + b;
};
int main()
{
std::cout << Calc::SUM<3, 5> << std::endl;
return 0;
}

c++ syntax: error conversion from some_type to non-scalar_type requested

Line 1 causes error: conversion from ‘C<void()>’ to non-scalar type ‘C<void (*)()>’ requested. I know I can write it as line 2, but how can I use the make_class() and assign it to a variable?
#include <iostream>
using namespace std;
template<class T> class C {
T f;
public:
C(T ff) : f(ff) {}
};
template<class Ft> C<Ft> make_class(const Ft& f)
{
return C<Ft>(f);
}
void f()
{
cout << "f()" << endl;
}
int main()
{
// C<void(*)()> v = make_class(f); // line 1
C<void(*)()> v(f); // line 2
return 0;
}
Another question is from this link. The code is shown as follows. How to understand line 3?
template <typename F>
struct foo {
F f;
void call() {
f();
}
};
void function() {
std::cout << "function called" << std::endl;
}
int main() {
foo<void(*)()> a = { function }; // line 3: { } is an array?
a.call();
}
Thanks.
A function type and a pointer to function types are different types in the language. While in most contexts the former will decay to the latter, when used as template arguments they generate two unrelated types (different instantiations of a template yield unrelated types).
The deduced type is const reference to function, not pointer to function. A simple workaround is dropping the const & from the function signature which will force the decay to a pointer to function (you cannot pass functions by value).
Regarding the second question, that is called aggregate-initialization, which is in fact the same initialization performed for arrays (arrays being a subset of aggregates).

How do I detect if a template parameter is a builtin or not?

I want to use SFINAE to stop from explicitly calling the destructor because MSVS 2010 considers it an error when done on a builtin type pointer.
How would I do this?
You might look at it from the wrong angle: You shouldn't exclude what does not work, you should detect what does work. In your case, you are trying to check if a given type T is a class and hence you could call the destructor.
That said, you want std::is_class. If it is not available for your compiler, there is Boost.TypeTraits' boost::is_class available which works with VC++ 8 and newer.
This shows how to specialize a function so it is called for fundamental data types in C++.
template < class T>
void delete_object(T, typename std::enable_if<std::is_arithmetic<T>::value>::type* = 0) {
// Do nothing because this is not an object
}
template<class T>
void delete_object(T* object) {
delete object;
}
int main()
{
int arithmetic1 = 1;
delete_object(arithmetic1);
float arithmetic2 = 1;
delete_object(arithmetic2);
Object* object1 = new Object();
delete_object(object1);
return 0;
}
Here are the other fundamental tests
std::is_integral<> - 'char' up to 'long long'
std::is_floating_point - 'float' up to 'long double'
std::is_signed<> - signed types
std::is_unsigned<> - unsigned types
std::is_arithmetic - is_integral<> OR is_floating_point<>
std::is_fundamental<> - is_arithmetic<> OR 'void'
With the following type function we can determine whether a type is a class type:
// traits/isclasst.hpp
template<typename T>
class IsClassT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template<typename C> static One test(int C::*);
template<typename C> static Two test(…);
public:
enum { Yes = sizeof(IsClassT<T>::test<T>(0)) == 1 };
enum { No = !Yes };
};
This template uses SFINAME principle.
The following program uses this type function to test whether certain types and objects are class types:
// traits/isclasst.cpp
#include <iostream>
#include "isclasst.hpp"
class MyClass {
};
struct MyStruct {
};
union MyUnion {
};
void myfunc()
{
}
enumE{e1}e;
// check by passing type as template argument
template <typename T>
void check()
{
if (IsClassT<T>::Yes) {
std::cout << " IsClassT " << std::endl;
}
else {
std::cout << " !IsClassT " << std::endl;
}
}
// check by passing type as function call argument
template <typename T>
void checkT (T)
{
check<T>();
}
int main()
{
std::cout << "int: ";
check<int>();
std::cout << "MyClass: ";
check<MyClass>();
std::cout << "MyStruct:";
MyStruct s;
checkT(s);
std::cout << "MyUnion: ";
check<MyUnion>();
std::cout << "enum: ";
checkT(e);
std::cout << "myfunc():";
checkT(myfunc);
}
The program has the following output:
int: !IsClassT
MyClass: IsClassT
MyStruct: IsClassT
MyUnion: IsClassT
enum: !IsClassT
myfunc(): !IsClassT

Static class member

What's wrong with the code below? Latest version of g++ and clang both give error. I am sure I am missing something basic here.
#include <iostream>
struct Z
{
static const int mysize = 10;
};
Z f2();
int main()
{
std::cout << f2()::mysize << std::endl;
}
The motivation here is to be able to find out the size of an array using templates using code such as below. I know there are many ways, but just stumbled upon this idea.
template<int N> struct S
{
enum { mysize = N };
};
template<class T, int N> S<N> f(T (&)[N]);
int main()
{
char buf[10];
std::cout << f(buf)::mysize << std::endl;
}
f2() returns a value, not a type. You'd need to use the . operator on the return value instead of ::
The :: operator requires a type to be named on the lefthand side, while . allows for a value to be named. Your expression f2() does not name a type so it cannot be used in conjunction with ::.
As a side note, with a little more detail in the question we might be able to solve your real problem.
Your program contains two mistakes:
You are using the :: operator to access the member of an object. Use operator . ("dot") instead;
You declare function f2() and invoke it without defining it (this will give you a linker error).
Also, since static member variables are shared among all instances of a class (Z in this case), you do not need an object to access it;
Here is how you could fix your program:
#include <iostream>
struct Z
{
static const int mysize = 10;
};
Z f2() { return Z(); }
int main()
{
// Don't need an object to access a static variable...
std::cout << Z::mysize << std::endl;
// ...but if you really want to, do it this way...
std::cout << f2().mysize << std::endl;
}
Why don't you use this way to find out the size of array by templates:
#include <iostream>
template<int N> struct S
{
enum { mysize = N };
};
template<class T, int N> int f1(T (&)[N])
{
return N;
}
int main()
{
char buf[10];
std::cout << f1(buf) << std::endl;
}
And this one is closer to your variant:
template<class T, int N> S<N> f(T (&)[N])
{
S<N> foo;
return foo;
}
int main()
{
char buf[10];
std::cout << f(buf).mysize << std::endl;
}
Anyway, you will need to return an object from f and access it's member by ., not by ::.
But it's more probable that second variant will be slower, because first variant is fully compile-time, but in the second variant compiler may miss the optimization and don't optimize out the run-time creation of foo.
I think you need to add const int Z::mysize; after class declaration.