5

The Dr.Dobb's article A Portable "typeof" Operator said

But you cannot use a class template to extract a type from an expression, as you can with function templates or overloading. (If the expression is a name with external linkage it is possible to implement typeof with class templates by using a template non-type parameter, but this is not very useful.)

Is the bolded sentence in parentheses correct? And if so how can a template non-type parameter be used to find the type of an expression with external linkage?

qbt937
  • 947
  • 7
  • 26
  • [Here's my "attempt"](http://ideone.com/G9hJKl) - it doesn't work, so I'm posting it as a comment. The issue is the "chicken and the egg" problem. Now, *if you could* somehow defer the type parameter declaration, or you could have `template`, it could work. – milleniumbug Dec 25 '14 at 19:43
  • @milleniumbug -- It's too bad that c++ requires a template declaration before it can be specialized. Otherwise it could work like `template struct { typedef T type };`. – qbt937 Dec 26 '14 at 03:43
  • I don't think the author of that Dr.Dobb's article was thinking that he could take the type of an expression like @milleniumbug was trying to do, because that wouldn't explain the need for it to be external linkage. – qbt937 Dec 26 '14 at 03:49
  • 1
    @qbt937 Actually, the external linkage is the reason I tried my attempts, see [this answer, with relevant standard quote](http://stackoverflow.com/a/15867521/1012936). Although this specific question is about C++11, as far as I remember, the linkage issue is relevant also in C++03. – milleniumbug Dec 26 '14 at 11:59

2 Answers2

2

There is no way in C++03 to implement typeof without using sizeof. The closest useful alternative is to extract the type using a function template which returns the desired type.

template<typename T>
struct Type
{
};

template<typename T>
Type<T> makeType(T)
{
    return Type<T>();
}


int main()
{
    int i;

    makeType(2 + 2); // Type<int>
    makeType(&i); // Type<int*>
}

The following technique uses function templates in C++03 to extract the type and value of any expression that can be used in a template argument.

template<typename T, T value>
struct NonType
{
};


template<typename T>
struct Type
{
    template<T value>
    static NonType<T, value>
        makeNonType()
    {
        return NonType<T, value>();
    }
};

template<typename T>
Type<T> makeType(T)
{
    return Type<T>();
}


#define MAKE_NONTYPE(e) makeType(e).makeNonType<e>()

int i;

int main()
{
    MAKE_NONTYPE(2 + 2); // NonType<int, 4>
    MAKE_NONTYPE(&i); // NonType<int*, i>
}

The following answer shows a practical use of this technique to extract the type and value of a pointer to member function expression: How to allow templated functor work on both member and non-member functions

Community
  • 1
  • 1
willj
  • 2,991
  • 12
  • 24
  • 1
    You do indeed get an expression of type `NonType`, but since you don't have `typeof` or `decltype`, you still cannot use that to refer to that type. I'm sorry, but I don't think this is useful here. –  Dec 26 '14 at 10:57
  • It's not `typeof` or `decltype`, but it's a useful alternative for solving a subset of the problems to which they apply. – willj Dec 26 '14 at 11:17
  • @qbt937 ... for what? This isn't a workaround AFAICS. – Columbo Dec 26 '14 at 20:43
2

It does not work in C++03 - the approach is actually nonsensical, I assume the author did not quite think this idea through.

However, with implicit template parameters (as proposed for C++1Z) this could actually work:

template <using typename T, T&> struct infer {using type = T;};

int a;
infer<a>::type // int

This still doesn't detect if a is a reference though.

Columbo
  • 60,038
  • 8
  • 155
  • 203