'reinterpret_cast':无法使用boost.dll从'重载函数'转换为'intptr_t'

时间:2018-08-22 12:57:49

标签: c++ boost

我正在使用Boost.dll

开发插件系统
#include <boost/config.hpp>
#include <boost/dll/alias.hpp>
#include <memory>

class base {
public:
  base(){};
  ~base(){};
  template <typename T>
  static std::shared_ptr<base> create() {
    return std::make_shared<T>();
  }
  virtual void do1() = 0;
};

class derived : public base {
public:
  derived(){};
  ~derived(){};
  virtual void do1() override {}
};

BOOST_DLL_ALIAS(base::create<derived>, // <-- this function is exported with...
                create_plugin          // <-- ...this alias name
)

// auto a = base::create<derived>();

当我尝试在BOOST_DLL_ALIAS宏中使用工厂方法时,出现如下错误。

cl /c /ID:\Download\Compressed\boost_1_67_0 a.cpp

Microsoft (R) C/C++ Optimizing Compiler Version 19.12.25834 for x86

Copyright (C) Microsoft Corporation.  All rights reserved.

a.cpp

a.cpp(27): error C2440: 'reinterpret_cast': cannot convert from 'overloaded-function' to 'intptr_t'

a.cpp(27): note: Context does not allow for disambiguation of overloaded function

在调用工厂方法时没有BOOST_DLL_ALIAS宏(如上一条注释行所示),它将得到很好的编译。

3 个答案:

答案 0 :(得分:2)

// this really does nothing:
template<class R, class...Args>
R(*to_fptr( R(*f)(Args...) ))(Args...) {
    return f;
}
// except avoid the bug in MSVC:
BOOST_DLL_ALIAS(to_fptr(base::create<derived>),
            create_plugin
)

that should fix it.

MSVC seems to break when you try to cast from the name of a template function to a intptr_t. This is a bug.

The above workaround changes it from directly dealing with the name of a template function to just a function pointer. By breaking the overload resolution and the cast to intptr_t apart, MSVC no longer chokes.

You could probably also do:

template<class T>
T identity( T t ) { return std::move(t); }

instead of to_fptr.

to_fptr is a function that takes a function pointer and returns it. The syntax to return a function pointer from a function is a bit ridiculous, which is why it is hard to read.

答案 1 :(得分:1)

This should do the trick:

BOOST_DLL_ALIAS(std::function<std::shared_ptr<base>(void)>(base::create<derived>), // <-- this function is exported with...
    create_plugin          // <-- ...this alias name
)

Indeed it seems MSVC has a bug here, as there should be no problem taking such an expression base::create<derived> and treating it directly as a function pointer. So instead, we "feed it a function pointer" ourselves using the magic of std::function.

I've chosen to use std::function as it involves no writing of any kind of wrapping code and relies directly on intent-delivering standard c++ code.

And of course don't forget to #include <functional> : )

答案 2 :(得分:1)

Inspired by this tangentially related answer, I found another solution:

const void * create_plugin =
    reinterpret_cast<const void*>(
        reinterpret_cast<std::intptr_t>(
            reinterpret_cast<std::decay_t<decltype(&base::create<derived>)> >(
                &base::create<derived>
            )
        )
    );

https://godbolt.org/z/NVGz_0