Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to instantiate all the c++ template sizes at compile time?

The c++/cli template below is working, but it seems like there ought to be a way to generalize the template further or add a helper that can create the template instances at compile time.

Was thinking something like http://en.cppreference.com/w/cpp/utility/integer_sequence might work, but need some assistance with the helper / implementer function.

Simplified main to demonstrate the desired syntax vs what is currently used:

int main(array<String^>^ args) {

    // the actual number of possible char lengths is sparse (generally)
    // but the API allows for 1-1024
    List<int>^ varList = gcnew List<int>();
    varList->Add(40);
    varList->Add(80);
    varList->Add(128);

    SortedList<int, List<String^>^>^ allStrings = gcnew SortedList<int, List<String^>^>();

    // want something like this, but the compiler complains that 
    // the template is invalid expectes compile-time constant expressions
    for each(int key in varList) {
        allStrings->Add(key, UpdateTest<key>());
    }

    // this works, but has 1024 lines of case N:
    for each(int key in varList) {
        switch (key) {
        case 1: allStrings->Add(key, UpdateTest<1>());
        case 2: allStrings->Add(key, UpdateTest<2>());
        case 3: allStrings->Add(key, UpdateTest<3>());
            //... all 1024 possible char[N] sizes...
        case 1024: allStrings->Add(key, UpdateTest<1024>());
        }
    }
}

Template works with the 1024 switch case N: calls. Is there a way to have a helper / implementer instantiate all 1024 without the cases?

template <std::size_t N> List<String^>^ APIwrapper::UpdateTest() {
    typedef char CHARX[N];  // N valid for 1 to 1024
    CHARX vals[MAXFIELDS];

    // NATIVE C++ VendorAPI(short, void*) vals is the address of the word aligned destination data
    int count = VendorAPI(N, &vals); 

    List<String^>^ retList = gcnew List<String^>();

    for (int c = 0; c < count; c++) {
        CHARX temp;
        strncpy(temp, vals[c], N);  // \0 terminated char arrays
        String^ x = gcnew String(temp);
        retList->Add(x->Substring(0, N)->Trim());
    }
    return retList;
}
like image 974
codebender Avatar asked Jan 04 '23 07:01

codebender


1 Answers

Following answer works for c++14, I don't know if it's compatible with cli.

You can use templates to generate a std::array of function pointers:

using UpdateTestPtr = decltype(&UpdateTest<0>);

// Struct used to generate the array's content.
template<typename Sequence>
struct UpdateTestArrayImpl;

// Specialization used to get the values in the integer sequence.
template<std::size_t... indices>
struct UpdateTestArrayImpl<std::integer_sequence<std::size_t,indices...>> {
    static constexpr std::array<UpdateTestPtr,sizeof...(indices)> value{UpdateTest<indices>...};
};

// Factorise sequence creation
template<std::size_t N>
using UpdateTestArray = UpdateTestArrayImpl<std::make_index_sequence<N>>;

static constexpr std::size_t N = 512;
// The array is needed at runtime. Create a normal (not constexpr) instance.
static std::array<UpdateTestPtr,N> functionArray = UpdateTestArray<N>::value;

And turn the switch/case into an array lookup:

for each(int key in varList) {
    allStrings->Add(key, functionArray[key]());
}

Live demo

Some compilers might produce a "template instantiation depth" error, depending on how make_integer_sequence is implemented. The max limit of recursion depth can normally be increased with compiler options.

like image 151
Vincent Saulue-Laborde Avatar answered Feb 03 '23 14:02

Vincent Saulue-Laborde