这是Boost类型擦除库中的一个错误吗?

huangapple go评论65阅读模式
英文:

Is this a bug in boost type erasure library?

问题

在Windows环境和C++ Builder 11.3中使用boost类型擦除库时,我遇到了编译错误。

在C++ Builder 11.3 Windows VCL应用程序中,我在一个窗体的.cpp文件中包含了以下头文件:

#ifndef BOOST_TEST_H
#define BOOST_TEST_H

#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/any_cast.hpp>
#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/operators.hpp>
#include <boost/type_erasure/member.hpp>
#include <boost/type_erasure/free.hpp>
#include <boost/mpl/vector.hpp>

namespace boost {
BOOST_TYPE_ERASURE_MEMBER(ReadStatus)
}

#endif

我收到以下错误消息:

[bcc32c Error] member11.hpp(46): expected identifier

这将我带到了boost头文件member111.hpp,第42行(boost 1.82.0版本):

template<class P, template<class ...> class interface, class Sig, class Concept, class Base, class ID>
using choose_member_interface = typename ::boost::mpl::if_c< ::boost::is_reference<P>::value,
    typename ::boost::mpl::if_c< ::boost::type_erasure::detail::is_non_const_ref<P>::value,
        interface<Sig, Concept, Base, const ID>,
        Base
    >::type,
    interface<Sig, Concept, Base, ID>
>::type;

问题在于,因为C++ Builder VCL for Windows已经引入了Windows头文件,包括combaseapi.h,在第170行定义了'interface'为其他内容,这会干扰boost在上面的代码中使用它...

如果我的头文件用于已经包含Windows.h的代码中,我可以在MSVC中复制这个示例...

我可以通过编辑boost的codegear.hpp(其中包含了C++ Builder特定的内容)来“修复”它,以取消定义'interface',或者甚至更改member11.hpp中的代码,将interface重命名为interface_(或任何唯一的任意值):

template<class P, template<class ...> class interface_, class Sig, class Concept, class Base, class ID>
using choose_member_interface = typename ::boost::mpl::if_c< ::boost::is_reference<P>::value,
    typename ::boost::mpl::if_c< ::boost::type_erasure::detail::is_non_const_ref<P>::value,
        interface_<Sig, Concept, Base, const ID>,
        Base
    >::type,
    interface_<Sig, Concept, Base, ID>
>::type;

我对任何一种“修复”都不满意,因为我不想编辑boost并可能在以后产生副作用,肯定会有维护问题。

问题:

有更好的解决方法吗?

Andy

英文:

If I use the boost type erasure library in a Windows environment and C++ Builder 11.3 I get compilation errors.

In a C++ Builder 11.3 Windows vcl application I include this header file in a form's .cpp file:

#ifndef BOOST_TEST_H
#define BOOST_TEST_H

#include &lt;boost/type_erasure/any.hpp&gt;
#include &lt;boost/type_erasure/any_cast.hpp&gt;
#include &lt;boost/type_erasure/builtin.hpp&gt;
#include &lt;boost/type_erasure/operators.hpp&gt;
#include &lt;boost/type_erasure/member.hpp&gt;
#include &lt;boost/type_erasure/free.hpp&gt;
#include &lt;boost/mpl/vector.hpp&gt;

namespace boost {
BOOST_TYPE_ERASURE_MEMBER(ReadStatus)
}

#endif

I get this error message:

[bcc32c Error] member11.hpp(46): expected identifier

This takes me to boost header member111.hpp, line 42 (boost 1.82.0)

template&lt;class P, template&lt;class ...&gt; class interface, class Sig, class Concept, class Base, class ID&gt;
using choose_member_interface = typename ::boost::mpl::if_c&lt; ::boost::is_reference&lt;P&gt;::value,
	typename ::boost::mpl::if_c&lt; ::boost::type_erasure::detail::is_non_const_ref&lt;P&gt;::value,
		interface&lt;Sig, Concept, Base, const ID&gt;,
		Base
	&gt;::type,
	interface&lt;Sig, Concept, Base, ID&gt;
&gt;::type;

The problem is that, because C++ Builder VCL for windows has already pulled in the windows headers, including combaseapi.h, which in line 170 had defined 'interface' as something else and this interferes with boost's use of it in the above code...

I can replicate the example in MSVC if my header is used in code that has already incorporated Windows.h...

I can 'fix' it by editing boost's codegear.hpp (where C++ Builder specific stuff resides) to undefine 'interface' or even change the code in member11.hpp to rename interface to interface_ (or any unique arbitrary value):

template&lt;class P, template&lt;class ...&gt; class interface_, class Sig, class Concept, class Base, class ID&gt;
using choose_member_interface = typename ::boost::mpl::if_c&lt; ::boost::is_reference&lt;P&gt;::value,
	typename ::boost::mpl::if_c&lt; ::boost::type_erasure::detail::is_non_const_ref&lt;P&gt;::value,
		interface_&lt;Sig, Concept, Base, const ID&gt;,
		Base
	&gt;::type,
	interface_&lt;Sig, Concept, Base, ID&gt;
&gt;::type;

I'm not happy with either 'fix' because I don't want to edit boost and maybe get side effects later and definitely a maintenance issue going on.

Question:

Is there a better fix?

Andy

答案1

得分: 1

请注意,以下是翻译的内容:

问题在于,因为 C++ Builder VCL for Windows 已经引入了 Windows 头文件,包括 combaseapi.h,在第170行定义了'interface'为其他内容,这会干扰 boost 的功能。

解决方法是在此之前不包含有问题的头文件,根本不包含它们,或以其他方式使有问题的头文件表现良好,例如使用预处理器,可以在此处找到描述:https://stackoverflow.com/questions/1394910/how-to-tame-the-windows-headers-useful-defines

英文:

You answer your question:

> The problem is that, because C++ Builder VCL for windows has already
> pulled in the windows headers, including combaseapi.h, which in line
> 170 had defined 'interface' as something else and this interferes with
> boost's

The solution is to not include the offending headers before that point, not include them at all, or otherwise cause the offending header to behave well e.g. using preprocessor described here: https://stackoverflow.com/questions/1394910/how-to-tame-the-windows-headers-useful-defines

答案2

得分: 0

经过与Embarcadero支持团队的讨论以及在boost-users邮件列表中的讨论,我们一致同意最佳修复方法是修改boost的member11.hpp文件如下所示:

template<class P, template<class ...> class Interface, class Sig, class Concept, class Base, class ID>
using choose_member_interface = typename ::boost::mpl::if_c< ::boost::is_reference<P>::value,
    typename ::boost::mpl::if_c< ::boost::type_erasure::detail::is_non_const_ref<P>::value,
        Interface<Sig, Concept, Base, const ID>,
        Base
    >::type,
    Interface<Sig, Concept, Base, ID>
>::type;

将interface重命名为Interface以避免命名冲突。

这是因为:

  1. C++ Builder VCL Windows项目以一种导致命名冲突的方式引入了Windows.h,而应用程序开发人员无法阻止这种情况。
  2. 如果C++ Builder应用程序是多线程的,那么boost会引入Windows.h,因为它用于支持线程。因此,仅仅包含boost头文件就会导致命名冲突。

Boost的修复方法非常简单且自包含...

这已经在boost类型擦除库的问题#20中修复了。

英文:

After discussions with Embarcadero support and in the boost-users mailing list, it was agreed that the best fix was to alter boost's member11.hpp as follows:

template&lt;class P, template&lt;class ...&gt; class Interface, class Sig, class Concept, class Base, class ID&gt;
using choose_member_interface = typename ::boost::mpl::if_c&lt; ::boost::is_reference&lt;P&gt;::value,
    typename ::boost::mpl::if_c&lt; ::boost::type_erasure::detail::is_non_const_ref&lt;P&gt;::value,
        Interface&lt;Sig, Concept, Base, const ID&gt;,
        Base
    &gt;::type,
    Interface&lt;Sig, Concept, Base, ID&gt;
&gt;::type;

renaming interface to Interface to avoid the naming clash.

This is necessary because:

  1. C++ Builder VCL Windows projects bring Windows.h in a way that causes the naming clash and the app developer can't prevent this
  2. If a C++ Builder application is multi-threaded then boost will bring in Windows.h as it uses it to support threads. So simply including the boost headers causes the naming clash...

Boost's fix is simple and self-contained...

This was fixed as issue #20 in the boost type erasure library.

huangapple
  • 本文由 发表于 2023年6月26日 16:16:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76554793.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定