5

Xcode 6.1 の clang バージョン (LLVM 3.5svn ベースの clang-600.0.54) を使用して次のコードをコンパイルしようとすると、-std=c++11よく-stdlib=libc++わからないエラーが表示されます。

#include <functional>

struct Impl
{
    typedef std::function<void ()> L;
    L l;
    int i;
};

struct Hndl
{
    Impl* impl;
    Hndl(Impl* i): impl(i) {}
    ~Hndl() noexcept(false) {}
};

int main(int argc, char * argv[]) {
    Hndl h(new Impl());
    h.impl->l = [=]
    {
        h.impl->i = 42;
    };
    return 0;
}

結果:

In file included from t.cpp:1:
/Applications/Xcode-6.1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1293:52: error: exception specification of overriding
      function is more lax than base version
template<class _FD, class _Alloc, class _FB> class __func;
                                                   ^
/Applications/Xcode-6.1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1593:13: note: in instantiation of template class
      'std::__1::__function::__func<<lambda at t.cpp:20:14>, std::__1::allocator<<lambda at t.cpp:20:14> >, void ()>' requested here
        if (sizeof(_FF) <= sizeof(__buf_) && is_nothrow_copy_constructible<_Fp>::value)
            ^
/Applications/Xcode-6.1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1697:5: note: in instantiation of function template
      specialization 'std::__1::function<void ()>::function<<lambda at t.cpp:20:14> >' requested here
    function(_VSTD::forward<_Fp>(__f)).swap(*this);
    ^
t.cpp:20:12: note: in instantiation of function template specialization 'std::__1::function<void ()>::operator=<<lambda at t.cpp:20:14> >' requested here
        h.impl->l = [=]
                  ^
/Applications/Xcode-6.1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1281:39: note: overridden virtual function is here
    _LIBCPP_INLINE_VISIBILITY virtual ~__base() {}
                                      ^
1 error generated.

どういうわけかofImpl::L::~L()を継承しているように見えますが、その理由はわかりません。興味深いことに、ラムダ内への割り当てをコメントアウトすると、同じコードがコンパイルされます。から仕様を削除してもコンパイルされますが、それが必要です (理由を説明するには少し長くなりますが、そうします)。ラムダが参照によってキャプチャされた場合もコンパイルしますが、ここでのポイントは、実装を共有するハンドルをコピーできることです。に追加しても役に立ちません。noexcept(false)Hndl::~Hndl()h.impl->inoexcept(false)Hndl::~Hndl()noexcept(true)Impl::~Impl()

ideone.com の c++11 コンパイラは、喜んでそのままコンパイルします。

ここで何が起こっているのか誰か説明してくれませんか?

4

3 に答える 3

3

ラムダの captureshには、スローされる可能性のあるデストラクタがあるため、ラムダのクロージャ タイプにも、スローされる可能性のあるデストラクタがあります。

それを念頭に置いて、問題を次のように減らすことができます。

#include <functional>

struct F
{
    void operator()() { }

    ~F() noexcept(false) {}
};

int main() {
    std::function<void ()> f = F{};
}

libc++の はstd::function、libc++ のバグのように見える nothrow デストラクタなしでは、呼び出し可能な型を格納できないようです。

noexceptエラー メッセージから、デストラクタに明示的に追加するのと同じくらい簡単に修正できるように見えますが__func、実装に慣れていないため、それほど簡単ではない可能性があります。

Hndl型をデストラクタで別の型にラップする以外に明らかな回避策noexceptは見当たりません。そのため、ラムダでキャプチャしても、ラムダにデストラクタが含まれることはありませんnoexcept(false)。私はこのようなことを試しましたが、libc ++には同様の問題があるようですshared_ptr:

    std::function<void ()> f = std::bind(&Hndl::operator(), std::make_shared<Hndl>());
于 2014-10-31T12:54:17.770 に答える
1

Hndl問題は、ラムダで値によってキャプチャされ、デストラクタがその定義に特に明記されていないため、std::functionデストラクタとして扱われることだと思います。noexcept(true)したがって、デストラクタHndlでインスタンスを安全に破棄することはできませんl。メンバーの割り当てがラムダから削除されるとエラーが消える理由については、キャプチャされた値がコンパイラによって最適化されている可能性が最も高いです。

于 2014-10-31T12:28:04.213 に答える