3

可動のみの型 (たとえば ) を受け入れるコールバック関数を呼び出す関数がありますunique_ptr

template <typename Function>
void foo(const Function& function) {
    BOOST_CONCEPT_ASSERT((
            boost::UnaryFunction<Function, void, std::unique_ptr<Bar>));
    auto bar = std::make_unique<Bar>();
    ...
    function(std::move(bar));
}

このコードをコンパイルしようとすると、BOOST_CONCEPT_ASSERT行がunique_ptr. 行を削除すると、コードは正常に機能します。Boost.Concept ライブラリは移動セマンティクスをサポートしていないようです。私自身の概念クラスを書かずに、これに対する回避策はありますか (ちなみに、左辺値と右辺値の両方を引数としてサポートするのは非常に単純ではありません)。

4

2 に答える 2

2

そのとおりです。残念ながら、UnaryFunction概念としては次のように書かれています。

  BOOST_concept(UnaryFunction,(Func)(Return)(Arg))
  {
      BOOST_CONCEPT_USAGE(UnaryFunction) { test(is_void<Return>()); }

   private:
      void test(boost::mpl::false_)
      {    
          f(arg);               // "priming the pump" this way keeps msvc6 happy (ICE)
          Return r = f(arg);
          ignore_unused_variable_warning(r);
      }    

      void test(boost::mpl::true_)
      {    
          f(arg); // <== would have to have std::move(arg)
                  // here to work, or at least some kind of
                  // check against copy-constructibility, etc.
      }    

#if (BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(4) \
                      && BOOST_WORKAROUND(__GNUC__, > 3)))
      // Declare a dummy construktor to make gcc happy.
      // It seems the compiler can not generate a sensible constructor when this is instantiated with a refence type.
      // (warning: non-static reference "const double& boost::UnaryFunction<YourClassHere>::arg"
      // in class without a constructor [-Wuninitialized])
      UnaryFunction();
#endif

      Func f;
      Arg arg; 
  };

は左辺値で渡されるためarg、Boost.Concepts で動作させる方法はありません。直接。ただし、ハックを書くことはできます。有効なチェックを呼び出しているだけなので、 に変換可能f(arg)な のローカル型を構築できます。あれは:argunique_ptr<Bar>

template <typename Function>
void foo(Function f)
{
    struct Foo {
        operator std::unique_ptr<int>();
    };

    BOOST_CONCEPT_ASSERT((
            boost::UnaryFunction<Function, void, Foo>));

    f(std::make_unique<int>(42));
}

またはより一般的に:

template <typename T>
struct AsRvalue {
    operator T(); // no definition necessary
};

template <typename Function>
void foo(Function f)
{
    BOOST_CONCEPT_ASSERT((
            boost::UnaryFunction<Function, void, AsRvalue<std::unique_ptr<int>>>));

    f(std::make_unique<int>(42));
}

それはgccとclangでコンパイルされます(ただし、未使用のtypedefについてclangで警告が表示されます)。ただし、その時点で、独自のコンセプトを書き出すだけで機能させる方が明確な場合があります。Piotr のようなものが最も簡単でしょう。

于 2015-08-14T15:14:24.870 に答える
2
#include <type_traits>
#include <utility>

template <typename...>
struct voider { using type = void; };

template <typename... Ts>
using void_t = typename voider<Ts...>::type;

template <typename, typename = void_t<>>
struct is_callable : std::false_type {};

template <typename F, typename... Args>
struct is_callable<F(Args...), void_t<decltype(std::declval<F>()(std::declval<Args>()...))>> : std::true_type {};

//...

static_assert(is_callable<Function&(std::unique_ptr<Bar>)>{}, "Not callable");

デモ

于 2015-08-14T15:08:03.447 に答える