Opened 10 years ago

Closed 10 years ago

Last modified 10 years ago

#7378 closed Bugs (fixed)

lookup_one_property fails if property tag not found

Reported by: Andreas Hehn <hehn@…> Owned by: Douglas Gregor
Milestone: To Be Determined Component: graph
Version: Boost 1.52.0 Severity: Problem
Keywords: lookup_one_property property_value Cc:

Description

boost::lookup_one_property<PropertyList,Tag>::found does not compile if Tag is not found in the PropertyList.

The problem originates from the lookup(...) function definition in the template specialization

  template <typename Tag, typename T, typename Base, typename PropName>
  struct lookup_one_property_internal<boost::property<Tag, T, Base>, PropName>: lookup_one_property_internal<Base, PropName> {
    private:
    typedef lookup_one_property_internal<Base, PropName> base_type;
    public:
    template <typename PL>
    static typename enable_if<is_same<PL, boost::property<Tag, T, Base> >, typename base_type::type&>::type
    lookup(PL& prop, const PropName& tag)

which requires the base class to provide a type member.

If the tag is not found the unspecialized template

    template <typename PList, typename PropName, typename Enable = void>
    struct lookup_one_property_internal {BOOST_STATIC_CONSTANT(bool, found = false);};

will be instantiated as Base where the compiler can't find any type member.

Attachments (2)

example.cpp (369 bytes ) - added by Andreas Hehn <hehn@…> 10 years ago.
demonstration code
property.hpp.patch (989 bytes ) - added by Andreas Hehn <hehn@…> 10 years ago.
patch

Download all attachments as: .zip

Change History (14)

by Andreas Hehn <hehn@…>, 10 years ago

Attachment: example.cpp added

demonstration code

comment:1 by Jeremiah Willcock, 10 years ago

Component: property_mapgraph
Resolution: wontfix
Status: newclosed

That change was made on purpose; it greatly helps error messages for using nonexistent property maps from graphs.

by Andreas Hehn <hehn@…>, 10 years ago

Attachment: property.hpp.patch added

patch

in reply to:  1 comment:2 by Andreas Hehn <hehn@…>, 10 years ago

Replying to jewillco:

That change was made on purpose; it greatly helps error messages for using nonexistent property maps from graphs.

Is there another way of checking the existence of some particular property tag then?

comment:3 by Jeremiah Willcock, 10 years ago

Look at lookup_one_property<...>::found. That takes a property list and a tag and determines if the property is present in the list. That doesn't give an easy way to test a graph for a given property, though.

comment:4 by anonymous, 10 years ago

That's what I thought, but lookup_one_property<...>::found is not false if the tag is not found, instead it just results in a compiler error.

comment:5 by Jeremiah Willcock, 10 years ago

What triggers the error in that case?

comment:6 by Andreas Hehn <hehn@…>, 10 years ago

That's what I reported in this bug report. Or am I missing something?

comment:7 by Andreas Hehn <hehn@…>, 10 years ago

The problem is that in the enable_if of the lookup(...) member function

template <typename Tag, typename T, typename Base, typename PropName>
  struct lookup_one_property_internal<boost::property<Tag, T, Base>, PropName>: lookup_one_property_internal<Base, PropName> {
    private:
    typedef lookup_one_property_internal<Base, PropName> base_type;
    public:
    template <typename PL>
    static typename enable_if<is_same<PL, boost::property<Tag, T, Base> >, typename base_type::type&>::type
    lookup(PL& prop, const PropName& tag)

typename base_type::type& does not depend on the template parameter of the template member function but only on the template parameters of the class. Therefore base_type::type is required to exist, even if lookup(...) is not used (or the enable_if<...> disables the function).

A solution could be to add a indirection which depeneds on PL, like

 template <class First, class Second>
 struct second_type {
     typedef Second type;
 };

...

    static typename enable_if<is_same<PL, boost::property<Tag, T, Base> >, typename second_type<PL,base_type>::type::type&>::type
    lookup(PL& prop, const PropName& tag)

which will prevent the compiler from resolving base_type::type unless lookup(...) is explicitly instantiated.

This way the general template lookup_one_property_internal does not need to define a type member to use lookup_one_property<...>::found.

But I have to admit that this solution looks a little ugly.

comment:8 by Jeremiah Willcock, 10 years ago

(In [80524]) Added void as default value of lookup_one_property_internal::type for "not found"; refs #7378

comment:9 by Andreas Hehn <hehn@…>, 10 years ago

Resolution: wontfix
Status: closedreopened

This was also my first approach, but unfortunately it doesn't solve the problem.

Since the return type of lookup(...) is type& the compiler will complain if type is void, as you can see if you try to compile my example code.

comment:10 by Jeremiah Willcock, 10 years ago

Resolution: fixed
Status: reopenedclosed

(In [80528]) Using lazy_enable_if to avoid "reference to void" errors for properties that are not found; fixes #7378

comment:11 by Andreas Hehn <hehn@…>, 10 years ago

Great! That solved the problem. I totally forgot about lazy_enable_if...

Could you also apply the same fix to struct lookup_one_property<const T, Tag> in line 159 of the same file?

Thanks for fixing the problem so quickly! :)

comment:12 by Jeremiah Willcock, 10 years ago

(In [80532]) Further fixed #7378 issue; refs #7378

Note: See TracTickets for help on using tickets.