Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Output the type of a typedef at compile time in C++ (specifically when an error occurs)

It is very difficult for me to explain this particular problem/question so please bear with me (I am having trouble with all my template related questions!).

Take this code as an example (note that the point of showing the code is to show a complex template hierarchy, not whether it makes sense):

#include <string>
#include <vector>
#include <list>

template <typename T>
struct Foo
{
  typedef typename T::value_type value_type;
  typedef typename T::value_type1 value_type1;
  typedef typename T::value_type2 value_type2;

  Foo() {}
  Foo(value_type1, value_type, value_type2) {}
  Foo(value_type, value_type1, value_type2) {}
};

template <typename T, typename T1, typename T2>
struct MiddleMan
{
  typedef T   value_type;
  typedef T1  value_type1;
  typedef T2  value_type2;
};

template <typename T>
struct MainClass
{
  typedef typename T::value_type value_type;
  typedef typename T::value_type1 value_type1;
  typedef typename T::value_type2 value_type2;

  typedef MainClass<T>  this_type;

  typedef Foo<this_type> iterator;
};

using namespace std;

int main()
{
  typedef MiddleMan<string, vector<string>, list<vector<string> > > mm;
  MainClass<mm>::iterator  a(1, 2, 3);

  return 0;
}

and assume this is the error you are getting

None of the 3 overloads could convert all the argument types

Note that I know in this instance, if you compile the code, the error message is not the same as above but the error message in my complex template code that I am currently working on is the above. I just presented a simplified example to help with the question.

Now I want to know the types of Foo, i.e. value_type, value_type1, value_type2 so that I can fix the error, without tracing back all the way to MiddleMan. The reason I don't want to trace manually is that the code can be quite complex template code where a trace back is very difficult to do.

I figured since the compiler has already figured out the types, it should be able to let me know, i.e. there should be an easy way to figure it out at compile time (maybe through a message in the output window) the types attached to the typedefs. Is there an easy way?


SOLUTION-EDIT: Here is another example that may help future SOer after reading the selected answer:

template <typename T> struct incomplete;

template <typename T, typename T2, typename T3>
class foo
{
public:
  typedef T value_type;
  typedef T2 value_type2;
  typedef T3 value_type3;
};

int main()
{
  // Assume the following type is much more complex
  typedef foo<float, int, char> type_i_am_having_trouble_with;

  // At this point you are instantiating it, and the program compiles (or maybe
  // not) and you have no idea what some of the typedefs stand for
  type_i_am_having_trouble_with b;

  // Use this to find out what the typedefs stand for
  incomplete<type_i_am_having_trouble_with::value_type> test; 
}

Output from Visual C++ 2008:

error C2079: 'test' uses undefined struct 'incomplete<T>'
1>        with
1>        [
1>            T=float
1>        ]
like image 946
Samaursa Avatar asked Jan 22 '12 01:01

Samaursa


People also ask

Is typedef compile time?

Yes it is resolved at compile time.

What does typedef int do?

The typedef keyword allows the programmer to create new names for types such as int or, more commonly in C++, templated types--it literally stands for "type definition". Typedefs can be used both to provide more clarity to your code and to make it easier to make changes to the underlying data types that you use.

Should typedef be public or private?

Any typedef used in the public interface of the class should be in the public section of the class. Rest should be private . Show activity on this post. If you declare as private , you will not be able to use them outside your class.

What is typedef Typename?

typedef is defining a new type for use in your code, like a shorthand. typedef typename _MyBase::value_type value_type; value_type v; //use v. typename here is letting the compiler know that value_type is a type and not a static member of _MyBase . the :: is the scope of the type.


1 Answers

There are a few tricks to get the compiler to show you the actual type of a typedef. One is to try to instantiate an incomplete type.

template<typename>
struct Printer;

typedef std::vector<int> foobartype;
Printer<foobartype> printer;

There is also boost::mpl::print which can actually issue a warning instead of erroring out.

All those techniques have to be used at the place where the typename is actually accessible so you will have to 'trace' through the code eventually.

Sadly, debugging template code is pretty much a black art and often you will have to play compiler and instantiate things in your head to get to the issue.

like image 110
pmr Avatar answered Sep 28 '22 00:09

pmr