geometry2 icon indicating copy to clipboard operation
geometry2 copied to clipboard

[windows] Fix ambiguous call for tf2::convert on MSVC

Open tfoote opened this issue 4 years ago • 3 comments

  • rework ambiguous call on MSVC.

Forward port of #444 to noetic

tfoote avatar May 13 '20 09:05 tfoote

@seanyen The patch from #444 doesn't forward port to noetic successfully. Could you take a look at why?

tfoote avatar May 13 '20 09:05 tfoote

I don't want to be disrespectful, but I pointed out the problem at multiple places. Please correct me if I'm wrong. The error message from the build is exactly the same as in #430:

11:56:08 test_convert.cpp:(.text._ZN3tf24impl9ConverterILb0ELb0EE7convertINS_10QuaternionEN5Eigen10QuaternionIdLi0EEEEEvRKT_RT0_[_ZN3tf24impl9ConverterILb0ELb0EE7convertINS_10QuaternionEN5Eigen10QuaternionIdLi0EEEEEvRKT_RT0_]+0x45): undefined reference to `void tf2::fromMsg<geometry_msgs::Quaternion_<std::allocator<void> >, Eigen::Quaternion<double, 0> >(geometry_msgs::Quaternion_<std::allocator<void> > const&, Eigen::Quaternion<double, 0>&)'
11:56:08 collect2: error: ld returned 1 exit status

IMHO, the whole conversion stuff boils down to something like (taken from here)

#include <iostream>
namespace msgs {
    struct A_msg { 
        A_msg(){} // for clang
    };
}

namespace datatypes {
    struct B_dt {};
}

namespace tf2 {
    template <class A, class B>
    void fromMsg(const A&, B&);

    template <class A, class B>
    void convert(const A& a, B& b) {
        fromMsg(a, b);
    }

    //template<>
    void fromMsg(const msgs::A_msg& a, datatypes::B_dt& b) {}
}

int main () {
    const msgs::A_msg a;
    datatypes::B_dt b;
    tf2::convert(a, b);
    std::cout << "Hello, world!\n";
}

Compilation/linking fails with GCC, Clang and MSVC (with /permissive- flag set). If you uncomment the template<> statement or if you reorder the tf2 namespace

namespace tf2 {
    void fromMsg(const msgs::A_msg& a, datatypes::B_dt& b) {}

    template <class A, class B>
    void fromMsg(const A&, B&);

    template <class A, class B>
    void convert(const A& a, B& b) {
        fromMsg(a, b);
    }
}

it works fine.

When the conversion is requested, tf2::convert() uses the templated forward declaration for tf2::fromMsg() in tf2/transform_functions.h. The point is that the corresponding function is not defined as a template specialization in tf2_eigen.h, but as a 'classic' overload. So, this correct overloaded function will only be chosen if it is defined before the generic forward declaration. Otherwise, these linking errors occur. The users have to take care on how they order their header #includes which is very error-prone.

gleichdick avatar May 21 '20 22:05 gleichdick

@tfoote Sorry this is out of my radar. I will be checking this one soon.

seanyen avatar Sep 10 '20 18:09 seanyen