Шаблон C ++ только при условии - PullRequest
0 голосов
/ 17 декабря 2018

Допустим, у меня есть оболочка для массивов:

template <const size_t i,typename T>
class ArrayWrapper {
    T arr [i] = {0};
public:
    //constructors and operators like [] ...
    void operator=(ArrayWrapper<i,T> & arrIn){
            for (size_t k =0; k< i;k++){
                arr[k] = arrIn[k];
            }
        }
};

Теперь я хочу иметь возможность назначать массивы другим массивам, например:

ArrayWrapper<2> arr1({1,2,3});
ArrayWrapper<2> arr2() = arr1;

Но теперь я хочудополнительно иметь возможность назначать более короткие массивы более длинным:

ArrayWrapper<3> arr1({1,2,3});
ArrayWrapper<4> arr2() = arr1;

здесь arr2 = {1,2,3,0}, но это не имеет смысла наоборот.

ArrayWrapper<3> arr1({1,2,3});
ArrayWrapper<2> arr2() = arr1;

Поскольку мы теряем информацию здесь. Как мне сказать компилятору не разрешать перегрузку этого с помощью j> i?

{...in ArrayWrapper class
    template <size_t j> 
        void operator=(ArrayWrapper<j,T> & arrIn){
                for (size_t k =0; k< j;k++){
                    arr[k] = arrIn[k];
                }
            }
...}

Я попробовал это:

template <size_t std::enable_if< j<=i>::j>
void operator=(ArrayWrapper<j,T> & arrIn){
        for (size_t k =0; k< j;k++){
            arr[k] = arrIn[k];
        }
    }

Но компилятор ненавидит это; (

Ответы [ 3 ]

0 голосов
/ 17 декабря 2018

Вот рабочий пример, адаптированный из этого поста о кастинге шаблонов:

#include <iostream>
#include <initializer_list>
template < const size_t i, typename T >
class ArrayWrapper {
public:
    T arr[i] = { 0 };
    ArrayWrapper<i,T>(){ }
    ArrayWrapper<i,T>(std::initializer_list<const size_t> arrIn) {
        std::copy(arrIn.begin(), arrIn.end(), arr);
    }
    void copyArr(T *arr, T *arrIn) {
        for (size_t k = 0; k < i; k++) {
            arr[k] = arrIn[k];
        }
    }
    void operator=(ArrayWrapper<i,T> & arrIn) {
        copyArr(arr, arrIn);
    }
    template < const size_t j, typename T >
    operator ArrayWrapper<j,T>() {
        ArrayWrapper<j,T> result;
        if (j < i) { 
            std::cout <<
            "Could not copy ArrayWrapper<" << i << ",T" << ">" 
                  << " into ArrayWrapper<" << j << ",T" << ">"
            << std::endl;
            return result;
        }
        copyArr(result.arr, arr);
        return result;
    }
    void print() {
        for (int j = 0; j < i; j++) {
            std::cout << arr[j] << ", ";
        }
        std::cout << std::endl;
    }
};
int main()
{
    ArrayWrapper<3, int> arr1({ 1, 2, 3 });
    ArrayWrapper<4, int> arr2 = arr1;
    arr1.print();
    arr2.print();
    ArrayWrapper<4, int> arr3({ 1, 2, 3 });
    ArrayWrapper<3, int> arr4 = arr3;
    arr3.print();
    arr4.print();
    system("PAUSE");
    return 0;
}
0 голосов
/ 17 декабря 2018

Это был ответ:

template <const size_t i,typename T>
class ArrayWrapper {
    T arr [i] = {0};
public:
    //constructors and operators like [] ...
    template <std::size_t j, typename = std::enable_if_t<j <= i>>
    void operator=(ArrayWrapper<i,T> & arrIn){
            for (size_t k =0; k< i;k++){
                arr[k] = arrIn[k];
            }
        }
};

THX to @HolyBlackCat!

0 голосов
/ 17 декабря 2018

Я бы просто использовал static_assert здесь.Поскольку i и j известны во время компиляции, вы можете использовать

template <size_t j> 
void operator=(ArrayWrapper<j,T> & arrIn)
{
    static_assert(i >= j, "Assigning a larger ArrayWrapper to a smaller ArrayWrapper is not allowed");
    for (size_t k =0; k< j;k++){
        arr[k] = arrIn[k];
    }
}

И теперь не только код не будет компилироваться, но вы получите действительно хорошее сообщение об ошибке.

...