[trick] Вывод типа в сообщении об ошибке в Visual Studio
От: Vain Россия google.ru
Дата: 09.08.14 18:09
Оценка: 118 (3)
Не так давно столкнулся с ситуацией, когда буст генерит кучу непонятных ошибок и не понятно в чём проблема.
В моём случае это был variant + операции поиска и выборки из него.
Вот пример.

  Заголовки
#include <boost/variant.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/find.hpp>
#include <boost/type_traits.hpp>

namespace mpl = boost::mpl;


  начальный пример
struct test_dummy
{
};

typedef boost::variant<int, long, test_dummy> variant_t0;
typedef mpl::vector<int, long, test_dummy> mpl_variant_t0;

template <typename V, typename T>
struct Find
{
  typedef typename mpl::at<V, mpl::int_<mpl::find<mpl_variant_t0, T>::type::pos::value> >::type type;
};

struct test : boost::static_visitor<>
{
  template <typename T>
  void operator()(const T & value) const
  {
    // на самом деле char здесь не виден как конкретный тип, это только для демонстрации проблемы
    typedef typename Find<mpl_variant_t0, char>::type found_t0;
    found_t0 i = 0; // как-то используем что имеем, здесь не важно как
  }
};

void main()
{
  variant_t0 variant_test1;
  // ... где-то в дебрях кода variant_test1 получает что-то или не получает, но мы не знаем что ...
  boost::apply_visitor(test(), variant_test1);
}


Под студией 2010 оно выдаст примерно следующее:
  ошибка компиляции (выводится 3 раза)

error C2440: 'initializing' : cannot convert from 'int' to 'found_t0'
No constructor could take the source type, or constructor overload resolution was ambiguous
boost_1_55_0\boost/variant/variant.hpp(1048) : see reference to function template instantiation 'void test::operator ()<const T>(const T &) const' being compiled
with
[
T=T0
]
boost_1_55_0\boost/variant/detail/visitation_impl.hpp(130) : see reference to function template instantiation 'void boost::detail::variant::invoke_visitor<Visitor>::internal_visit<const T>(T &,int)' being compiled
with
[
Visitor=const test,
T=T0
]
boost_1_55_0\boost/variant/detail/visitation_impl.hpp(173) : see reference to function template instantiation 'void boost::detail::variant::visitation_impl_invoke_impl<Visitor,VoidPtrCV,T>(int,Visitor &,VoidPtrCV,T *,boost::mpl::true_)' being compiled
with
[
Visitor=boost::detail::variant::invoke_visitor<const test>,
VoidPtrCV=const void *,
T=T0
]
boost_1_55_0\boost/variant/detail/visitation_impl.hpp(256) : see reference to function template instantiation 'void boost::detail::variant::visitation_impl_invoke<Visitor,VoidPtrCV,T0,NoBackupFlag>(int,Visitor &,VoidPtrCV,T *,NoBackupFlag,int)' being compiled
with
[
Visitor=boost::detail::variant::invoke_visitor<const test>,
VoidPtrCV=const void *,
NoBackupFlag=boost::variant<int,long,test_dummy>::has_fallback_type_,
T=T0
]
boost_1_55_0\boost/variant/variant.hpp(2367) : see reference to function template instantiation 'void boost::detail::variant::visitation_impl<first_which,first_step,Visitor,VoidPtrCV,boost::variant<T0_,T1,T2>::has_fallback_type_>(const int,const int,Visitor &,VoidPtrCV,boost::mpl::false_,NoBackupFlag,Which *,step0 *)' being compiled
with
[
Visitor=boost::detail::variant::invoke_visitor<const test>,
VoidPtrCV=const void *,
T0_=int,
T1=long,
T2=test_dummy,
NoBackupFlag=boost::variant<int,long,test_dummy>::has_fallback_type_,
Which=first_which,
step0=first_step
]
boost_1_55_0\boost/variant/variant.hpp(2389) : see reference to function template instantiation 'void boost::variant<T0_,T1,T2>::internal_apply_visitor_impl<Visitor,const void*>(int,int,Visitor &,VoidPtrCV)' being compiled
with
[
T0_=int,
T1=long,
T2=test_dummy,
Visitor=boost::detail::variant::invoke_visitor<const test>,
VoidPtrCV=const void *
]
boost_1_55_0\boost/variant/variant.hpp(2411) : see reference to function template instantiation 'void boost::variant<T0_,T1,T2>::internal_apply_visitor<boost::detail::variant::invoke_visitor<Visitor>>(boost::detail::variant::invoke_visitor<Visitor> &) const' being compiled
with
[
T0_=int,
T1=long,
T2=test_dummy,
Visitor=const test
]
boost_1_55_0\boost/variant/detail/apply_visitor_unary.hpp(76) : see reference to function template instantiation 'void boost::variant<T0_,T1,T2>::apply_visitor<const Visitor>(Visitor &) const' being compiled
with
[
T0_=int,
T1=long,
T2=test_dummy,
Visitor=test
]
test.cpp(117) : see reference to function template instantiation 'void boost::apply_visitor<test,const variant_t0>(const Visitor &,Visitable &)' being compiled
with
[
Visitor=test,
Visitable=const variant_t0
]



Ни намёка на то, что за тип такой found_t0.

В инете можно найти несколько способов показать тип. К примеру, способ с incomplete type error:
  пример с incomplete type
#define INCOMPLETE_TYPE_LOOKUP_BY_ERROR(type_name) \
  static_cast< ::util::incomplete_type_lookup< type_name > >(0);

namespace util
{
  template <typename T>
  struct incomplete_type_lookup;
}

struct test : boost::static_visitor<>
{
  template <typename T>
  void operator()(const T & value) const
  {
    typedef typename mpl::at<mpl_variant_t0, mpl::int_<mpl::find<mpl_variant_t0, T>::type::pos::value> >::type found_t0;
    INCOMPLETE_TYPE_LOOKUP_BY_ERROR(found_t0);
    //found_t0 i = 0;
  }
};


Но это не всегда работает. Компилятор из Visual Studio 2010 показывает не внутренний тип, а внешний:
  почти такая же бесполезная ошибка, вид сбоку 3 раза

error C2440: 'static_cast' : cannot convert from 'int' to 'util::incomplete_type_lookup<T>'
with
[
T=found_t0
]
Source or target has incomplete type
boost_1_55_0\boost/variant/variant.hpp(1048) : see reference to function template instantiation 'void test::operator ()<const T>(const T &) const' being compiled
with
[
T=T0
]
boost_1_55_0\boost/variant/detail/visitation_impl.hpp(130) : see reference to function template instantiation 'void boost::detail::variant::invoke_visitor<Visitor>::internal_visit<const T>(T &,int)' being compiled
with
[
Visitor=const test,
T=T0
]
boost_1_55_0\boost/variant/detail/visitation_impl.hpp(173) : see reference to function template instantiation 'void boost::detail::variant::visitation_impl_invoke_impl<Visitor,VoidPtrCV,T>(int,Visitor &,VoidPtrCV,T *,boost::mpl::true_)' being compiled
with
[
Visitor=boost::detail::variant::invoke_visitor<const test>,
VoidPtrCV=const void *,
T=T0
]
boost_1_55_0\boost/variant/detail/visitation_impl.hpp(256) : see reference to function template instantiation 'void boost::detail::variant::visitation_impl_invoke<Visitor,VoidPtrCV,T0,NoBackupFlag>(int,Visitor &,VoidPtrCV,T *,NoBackupFlag,int)' being compiled
with
[
Visitor=boost::detail::variant::invoke_visitor<const test>,
VoidPtrCV=const void *,
NoBackupFlag=boost::variant<int,long,test_dummy>::has_fallback_type_,
T=T0
]
boost_1_55_0\boost/variant/variant.hpp(2367) : see reference to function template instantiation 'void boost::detail::variant::visitation_impl<first_which,first_step,Visitor,VoidPtrCV,boost::variant<T0_,T1,T2>::has_fallback_type_>(const int,const int,Visitor &,VoidPtrCV,boost::mpl::false_,NoBackupFlag,Which *,step0 *)' being compiled
with
[
Visitor=boost::detail::variant::invoke_visitor<const test>,
VoidPtrCV=const void *,
T0_=int,
T1=long,
T2=test_dummy,
NoBackupFlag=boost::variant<int,long,test_dummy>::has_fallback_type_,
Which=first_which,
step0=first_step
]
boost_1_55_0\boost/variant/variant.hpp(2389) : see reference to function template instantiation 'void boost::variant<T0_,T1,T2>::internal_apply_visitor_impl<Visitor,const void*>(int,int,Visitor &,VoidPtrCV)' being compiled
with
[
T0_=int,
T1=long,
T2=test_dummy,
Visitor=boost::detail::variant::invoke_visitor<const test>,
VoidPtrCV=const void *
]
boost_1_55_0\boost/variant/variant.hpp(2411) : see reference to function template instantiation 'void boost::variant<T0_,T1,T2>::internal_apply_visitor<boost::detail::variant::invoke_visitor<Visitor>>(boost::detail::variant::invoke_visitor<Visitor> &) const' being compiled
with
[
T0_=int,
T1=long,
T2=test_dummy,
Visitor=const test
]
boost_1_55_0\boost/variant/detail/apply_visitor_unary.hpp(76) : see reference to function template instantiation 'void boost::variant<T0_,T1,T2>::apply_visitor<const Visitor>(Visitor &) const' being compiled
with
[
T0_=int,
T1=long,
T2=test_dummy,
Visitor=test
]
test.cpp(117) : see reference to function template instantiation 'void boost::apply_visitor<test,const variant_t0>(const Visitor &,Visitable &)' being compiled
with
[
Visitor=test,
Visitable=const variant_t0
]



Идея заключается в том, чтобы вызвать у неизвестного типа то, что у него быть не может, компилятор начнёт искать это что-то, раскрывая всё подряд, ну и раскроет и наш тип:
  наборчик для вскрывания типов %)
// generates compilation error and shows real type name (and place of declaration in some cases) in an error message

//// old C++ standard compatible
//#define UTIL_TYPE_LOOKUP_BY_ERROR(type_name) \
//  (*(typename ::util::type_lookup< type_name >::type*)0).operator ,(*(::util::dummy*)0)

// can be applied in a class, but requires `decltype` support
#define UTIL_TYPE_LOOKUP_BY_ERROR(type_name) \
    typedef decltype((*(typename ::util::type_lookup<type_name >::type*)0).operator ,(*(::util::dummy*)0)) _type_lookup_t

// the macro only for old msvc compiler which has more useful error output if a scope class and a type can be separated from each other
#ifdef _MSC_VER

#define UTIL_TYPE_LOOKUP_BY_ERROR_CLASS(class_name, type_name) \
  (*(typename ::util::type_lookup< class_name >::type_name*)0).operator ,(*(::util::dummy*)0)

#else

#define UTIL_TYPE_LOOKUP_BY_ERROR_CLASS(class_name, type_name) \
   UTIL_TYPE_LOOKUP_BY_ERROR(class_name::type_name)

#endif

namespace util
{
  struct dummy;
  template <typename T>
  struct type_lookup
  {
    typedef T type;
  };
}


  пример использования
struct test : boost::static_visitor<>
{
  template <typename T>
  void operator()(const T & value) const
  {
    typedef typename Find<mpl_variant_t0, char>::type found_t0;
    UTIL_TYPE_LOOKUP_BY_ERROR(found_t0);
    UTIL_TYPE_LOOKUP_BY_ERROR(mpl_variant_t0);
    UTIL_TYPE_LOOKUP_BY_ERROR(variant_t0);
    //found_t0 i = 0;
  }
};


  ошибки компиляции со вскрытыми типами

error C2039: ',' : is not a member of 'boost::mpl::void_'
boost_1_55_0\boost/mpl/void.hpp(29) : see declaration of 'boost::mpl::void_'
boost_1_55_0\boost/variant/variant.hpp(1048) : see reference to function template instantiation 'void test::operator ()<const T>(const T &) const' being compiled
with
[
T=T0
]
boost_1_55_0\boost/variant/detail/visitation_impl.hpp(130) : see reference to function template instantiation 'void boost::detail::variant::invoke_visitor<Visitor>::internal_visit<const T>(T &,int)' being compiled
with
[
Visitor=const test,
T=T0
]
boost_1_55_0\boost/variant/detail/visitation_impl.hpp(173) : see reference to function template instantiation 'void boost::detail::variant::visitation_impl_invoke_impl<Visitor,VoidPtrCV,T>(int,Visitor &,VoidPtrCV,T *,boost::mpl::true_)' being compiled
with
[
Visitor=boost::detail::variant::invoke_visitor<const test>,
VoidPtrCV=const void *,
T=T0
]
boost_1_55_0\boost/variant/detail/visitation_impl.hpp(256) : see reference to function template instantiation 'void boost::detail::variant::visitation_impl_invoke<Visitor,VoidPtrCV,T0,NoBackupFlag>(int,Visitor &,VoidPtrCV,T *,NoBackupFlag,int)' being compiled
with
[
Visitor=boost::detail::variant::invoke_visitor<const test>,
VoidPtrCV=const void *,
NoBackupFlag=boost::variant<int,long,test_dummy>::has_fallback_type_,
T=T0
]
boost_1_55_0\boost/variant/variant.hpp(2367) : see reference to function template instantiation 'void boost::detail::variant::visitation_impl<first_which,first_step,Visitor,VoidPtrCV,boost::variant<T0_,T1,T2>::has_fallback_type_>(const int,const int,Visitor &,VoidPtrCV,boost::mpl::false_,NoBackupFlag,Which *,step0 *)' being compiled
with
[
Visitor=boost::detail::variant::invoke_visitor<const test>,
VoidPtrCV=const void *,
T0_=int,
T1=long,
T2=test_dummy,
NoBackupFlag=boost::variant<int,long,test_dummy>::has_fallback_type_,
Which=first_which,
step0=first_step
]
boost_1_55_0\boost/variant/variant.hpp(2389) : see reference to function template instantiation 'void boost::variant<T0_,T1,T2>::internal_apply_visitor_impl<Visitor,const void*>(int,int,Visitor &,VoidPtrCV)' being compiled
with
[
T0_=int,
T1=long,
T2=test_dummy,
Visitor=boost::detail::variant::invoke_visitor<const test>,
VoidPtrCV=const void *
]
boost_1_55_0\boost/variant/variant.hpp(2411) : see reference to function template instantiation 'void boost::variant<T0_,T1,T2>::internal_apply_visitor<boost::detail::variant::invoke_visitor<Visitor>>(boost::detail::variant::invoke_visitor<Visitor> &) const' being compiled
with
[
T0_=int,
T1=long,
T2=test_dummy,
Visitor=const test
]
boost_1_55_0\boost/variant/detail/apply_visitor_unary.hpp(76) : see reference to function template instantiation 'void boost::variant<T0_,T1,T2>::apply_visitor<const Visitor>(Visitor &) const' being compiled
with
[
T0_=int,
T1=long,
T2=test_dummy,
Visitor=test
]
test.cpp(119) : see reference to function template instantiation 'void boost::apply_visitor<test,const variant_t0>(const Visitor &,Visitable &)' being compiled
with
[
Visitor=test,
Visitable=const variant_t0
]
error C2039: ',' : is not a member of 'boost::mpl::vector<T0,T1,T2>'
with
[
T0=int,
T1=long,
T2=test_dummy
]
error C2039: ',' : is not a member of 'boost::variant<T0_,T1,T2>'
with
[
T0_=int,
T1=long,
T2=test_dummy
]

[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Отредактировано 04.01.2018 22:29 Vain . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.