LoginSignup
2
0

More than 5 years have passed since last update.

C++で、実行時にstd::vectorの各要素を可変長引数関数の引数に、それぞれ入れられるか

Last updated at Posted at 2018-08-18

結論

できなさそうだ。一応、完全ではないがマクロでやればできる。
(18/08/21 1:48 追記)  コメントで、マクロを使わない実装を頂きました!

理由

可変長引数関数をカリー化して一つずつ引数を入れるというアプローチをとった。しかし、カリー化の際に使用するstd::bind(またはsprout::bind←可変長プレースホルダーが使えるここに詳細)は、引数を適用するたびに型が変わるようだ。そのため、std::vectorの、実行時にはわからないの要素数用のstd::bindはコンパイル時に作ることができないだろう。なので、実行時に可変長引数関数をカリー化し、std::vectorの要素一つ一つに引数を適用することはできなかった。(コンパイル時でも、要素数がわからなそう(std::vector::size()は定数式ではない)なのでできなそうだ)

コード例

#include <iostream>
#include <vector>
#include <utility>
#include <boost/any.hpp>
#include <sprout/functional.hpp>

int main()
{
    std::vector<int> v{10, 20, 30};  // 実行時に任意の要素数で構築したとする
    using sprout::placeholders::_va;  // 可変長引数プレースホルダー

    constexpr auto lambda = [](auto&&... args)  // 任意の可変長引数関数
    {
        (std::cout << ... << std::forward<decltype(args)>(args)) << '\n';
    };

    // forループの際に、型が変化するのでenyに入れた
    boost::any fn = sprout::bind(lambda, _va); 

    for (auto&& it : v)
    {
        // このfnの型を、コンパイル時には知ることができない
        // fn = sprout::bind(boost::any_cast<不明>(fn), it, _va);  
    }

    // boost::any_cast<不明>(fn)();

}

マクロを使った解決策

マクロを使って、可変長引数の引数の数それぞれのパターンを自動生成している。これは、それぞれの引数の数に対して、switch構文のcase一つ一つが対応するようにしている。これは一応動くが、生成されるコードの量は多くなっており、引数の数も制限されている。

#include <iostream>
#include <vector>
#include <utility>
#include <boost/preprocessor/enum.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>

int main()
{
    std::vector<int> v{10, 20, 30};  // 実行時に任意の要素数で構築したとする

    constexpr auto lambda = [](auto&&... args)  // 任意の可変長引数関数
    {
        (std::cout << ... << std::forward<decltype(args)>(args)) << '\n';
    };

// caseの数(0からBOOST_PP_LIMIT_REPEAT(256に展開)までの値)    
#define CASE_NUM 15

#define ARG(z, n, unused) v[n]
#define CASE(z, n, unused) \
    case n: \
        lambda(BOOST_PP_ENUM(n, ARG, unused)); \
        break;   

    switch (v.size())
    {
        BOOST_PP_REPEAT(CASE_NUM, CASE, unused)
    default:
        std::cout << "引数が多すぎます。 " 
            << CASE_NUM - 1 << "個までの引数にしてください。\n";
        break;    
    }

#undef CASE
#undef ARG
#undef CASE_NUM

}
2
0
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0