如何使用基于函数的值填充const std :: array <size_t,n =“”>

时间:2015-12-07 21:52:08

标签: c++ c++11 c++14

如何创建包含以下值的const std :: array f(0),f(1),...,f(N-1)其中f是任何函数:static constexpr size_t f(int index)? 当我确切知道N时,我可以明显地写

import android.media.MediaCodec;
import android.media.MediaFormat;

import com.google.common.base.Throwables;

import java.io.IOException;
import java.nio.ByteBuffer;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

/**
 * Class responsible for encoding.
 */
public class Encoder {
    private final MediaCodec encoder;
    private final Muxer muxer;
    private final MediaCodec.BufferInfo bufferInfo;
    private int trackIndex;


    public Encoder(String mimeType, MediaFormat format, Muxer muxer) {
        checkNotNull(mimeType);
        checkNotNull(format);
        checkNotNull(muxer);

        try {
            encoder = MediaCodec.createEncoderByType(mimeType);
            encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);

            this.muxer = muxer;
            bufferInfo = new MediaCodec.BufferInfo();
        } catch (IOException e) {
            throw Throwables.propagate(e);
        }
    }

    public MediaCodec getEncoder() {
        return encoder;
    }

    /**
     * Extracts all pending data from the encoder and forwards it to the muxer.
     * <p/>
     * If endOfStream is not set, this returns when there is no more data to drain.  If it
     * is set, we send EOS to the encoder, and then iterate until we see EOS on the output.
     * Calling this with endOfStream set should be done once, right before stopping the muxer.
     * <p/>
     * We're just using the muxer to get a .mp4 file (instead of a raw H.264 stream).
     */
    public void drain(boolean endOfStream) {
        final int TIMEOUT_USEC = 10000;

        if (endOfStream) {
            encoder.signalEndOfInputStream();
        }

        ByteBuffer[] encoderOutputBuffers = encoder.getOutputBuffers();
        while (true) {
            int encoderStatus = encoder.dequeueOutputBuffer(bufferInfo, TIMEOUT_USEC);
            if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
                // no output available yet
                if (!endOfStream) {
                    break;      // out of while
                }
            } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
                // not expected for an encoder
                encoderOutputBuffers = encoder.getOutputBuffers();
            } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                // now that we have the Magic Goodies, start the muxer
                trackIndex = muxer.addTrack(encoder.getOutputFormat());
            } else if (encoderStatus < 0) {
                // let's ignore it
            } else {
                ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
                checkState(encodedData != null, "encoderOutputBuffer %s was null", encoderStatus);

                if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
                    // The codec config data was pulled out and fed to the muxer when we got
                    // the INFO_OUTPUT_FORMAT_CHANGED status.  Ignore it.
                    bufferInfo.size = 0;
                }

                if (bufferInfo.size != 0) {
                    // adjust the ByteBuffer values to match BufferInfo (not needed?)
                    encodedData.position(bufferInfo.offset);
                    encodedData.limit(bufferInfo.offset + bufferInfo.size);

                    muxer.writeSampleData(trackIndex, encodedData, bufferInfo);
                }

                encoder.releaseOutputBuffer(encoderStatus, false);

                if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                    break;      // out of while
                }
            }
        }
    }

    public void release() {
        if (encoder != null) {
            try {
                encoder.stop();
            } catch (Exception e) {
            }
            encoder.release();
        }
    }
}

4 个答案:

答案 0 :(得分:4)

创建需要任意复杂初始化的常量的一般方法是简单地编写一个返回所需值的函数,然后在常量的初始化程序中调用它。例如:

dot

答案 1 :(得分:3)

它可能需要抛光,但这就是我的想法:

template <std::size_t... ns, typename Fn>
auto fill_helper(std::integer_sequence<std::size_t, ns...>, Fn&& fn) -> std::array<decltype(fn(std::size_t())), sizeof...(ns)>  {
    return {{fn(ns)...}};
} 

template <std::size_t N, typename Fn>
auto fill(Fn&& fn) {
    using seq = std::make_integer_sequence<std::size_t, N>;
    return fill_helper(seq(), std::forward<Fn>(fn));    
}

int main() {

    auto plus5 = [](std::size_t index) {
        return index + 5;
    };

    auto const as = fill<5>(plus5);
    for (auto&& a: as)
        std::cout << a;

}

优点是您使用正确的值初始化数组,而不是先初始化然后分配。

答案 2 :(得分:2)

如果你想在不创建外部函数的情况下进行常量初始化,你也可以这样做:

void SomeFunction() {

    const auto my_array = [](){
        auto a = array<SomeType, N>();
        for (size_t i = 0; i < a.size(); ++i)
            a[i] = f(i);
        return a;
    }(); // <-- Note that the lambda executes right away

    DoSomeStuff(my_array);
}

答案 3 :(得分:1)

使用lambda和std::generate

#include<array>
#include<algorithm> // generate
#include<cassert>
#include<iostream>

int f(int i){return i*i;}

int main(){
    const std::array<int, 5> a = []{
        std::array<int, 5> a;
        int n = 0;
        std::generate(a.begin(), a.end(), [&n]{ return f(n++); });
        return a;
    }();
    assert( a[4] == 16 );
}

http://coliru.stacked-crooked.com/a/60e2ec92e648519d