Почему мой объект constexpr не является constexpr внутри моей функции? - PullRequest
2 голосов
/ 21 января 2020

Я написал класс, который можно инициализировать и копировать во время компиляции, и использование объекта вне моей функции также работает во время компиляции. Теперь я хочу передать мой constexpr объект в функцию для выполнения некоторых вычислений, но компилятор выдает ошибку, что мой объект не является константным выражением.

Как мне написать свою функцию, чтобы использовать мой constexpr объект?

Использование G CC 9.2, C ++ 17, (опция CLion для использования C ++ 20 активирована)

Вот мой класс, моя функция и основной , Обратите внимание: не все определения даны, так как было бы много кода для сообщения.

template<std::size_t t1_skipPos, std::size_t t2_skipPos, typename T1, typename T2>
constexpr auto contraction(T1 tensor1, T2 tensor2){

    /*ERROR: tensor1 is not a constant expression*/
    auto sris_tensor1 = save_recreated_index_sequence<0, tensor1.indices_amount-2, 
         t1_skipPos, tensor1.indices_amount, DIM3>(tensor1.calculate_indices());

    return sris_tensor1;

}


template<typename T, typename ... Args>
class tensorBase{

    private:
        std::array<T, positive_natural_compiletime_pow<DIM3, std::tuple_size<Args...>::value>()> data;

    public:
        //std::vector<T> data = {};

        std::tuple<Args...> myTypeTup;

        std::size_t indices_amount =  std::tuple_size<Args...>::value;


    template<typename ... Element>
    constexpr tensorBase(Element&&... input) : data{input...} {};

    /* copy constructor */
    template<typename Tensor>
    constexpr tensorBase(const Tensor &oldObj){

        data = oldObj.get_data();

        myTypeTup = oldObj.myTypeTup;

        indices_amount = oldObj.indices_amount;

    }
/*
    template<typename Arr>
    constexpr tensorBase(Arr&& array) {
        data = array;
    };
*/
    constexpr auto calculate_indices() const{

        static_assert((std::tuple_size<Args...>::value <= 5), "tensor has to many indices");
        //auto l = std::tuple_size<Args...>::value;
        return cartesian_product<DIM3, std::tuple_size<Args...>::value>();
        //return cartesian_product_to_vec<DIM3, sizeof...(Args)+1>();
    };

    template<typename D>
    constexpr auto get_element(D&& val) const{
        return data[val];
    };

    constexpr auto get_data() const{
        return data;
    };
};

template<typename T, typename ... Args>
using tensor = tensorBase<T, std::tuple<Args...>>;

int main(){
    constexpr tensor<double, up_t, low_t, low_t> tensor1(11.0, 22.0, 33.0, 44.0, 55.0, 66.0, 77.0, 88.0, 99.0); /*OK*/
    constexpr tensor<double, up_t, low_t> tensor2(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9);/*OK*/
    constexpr auto copyObj1 = tensor1; /*OK*/
    constexpr auto indices = tensor1.indices_amount; /*OK*/
    constexpr auto indices1 = tensor1.calculate_indices(); /*OK*/

    constexpr auto sris_outside = save_recreated_index_sequence
        <0, tensor1.indices_amount-1,0,tensor1.indices_amount,2>(tensor1.calculate_indices()); /*OK*/

    constexpr auto contract = contraction<0,0>(tensor1, tensor2); /*Error*/

    return 0;
}

Сообщение об ошибке:

   In instantiation of ‘constexpr auto contraction(T1, T2) [with long unsigned int t1_skipPos = 0; long unsigned int t2_skipPos = 0; T1 = tensorBase<double, std::tuple<up_t, low_t, low_t> >; T2 = tensorBase<double, std::tuple<up_t, low_t> >]’:

error: no matching function for call to ‘save_recreated_index_sequence<0, (tensor1.tensorBase<double, std::tuple<up_t, low_t, low_t> >::indices_amount - 2), 0, tensor1.tensorBase<double, std::tuple<up_t, low_t, low_t> >::indices_amount, DIM3>(std::array<std::tuple<long unsigned int, long unsigned int, long unsigned int>, 27>)’
       61 |     auto sris_tensor1 = save_recreated_index_sequence<0, tensor1.indices_amount-2, t1_skipPos, tensor1.indices_amount, DIM3>(tensor1.calculate_indices());
          |                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

note: candidate: ‘template<long unsigned int offset, long unsigned int N, long unsigned int skipPos, long unsigned int length, long unsigned int times, class Arr> constexpr auto save_recreated_index_sequence(Arr&&)’
       46 | constexpr auto save_recreated_index_sequence(Arr&& arr){
          |                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 note:   template argument deduction/substitution failed:
    In file included from /home/martin/CLionProjects/tensor-library-v1/main.cpp:43:
 error: ‘tensor1’ is not a constant expression
       61 |     auto sris_tensor1 = save_recreated_index_sequence<0, tensor1.indices_amount-2, t1_skipPos, tensor1.indices_amount, DIM3>(tensor1.calculate_indices());
          |                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 note: in template argument for type ‘long unsigned int’
       61 |     auto sris_tensor1 = save_recreated_index_sequence<0, tensor1.indices_amount-2, t1_skipPos, tensor1.indices_amount, DIM3>(tensor1.calculate_indices());
          |                                                          ~~~~~~~~~~~~~~~~~~~~~~^~
error: ‘tensor1’ is not a constant expression
       61 |     auto sris_tensor1 = save_recreated_index_sequence<0, tensor1.indices_amount-2, t1_skipPos, tensor1.indices_amount, DIM3>(tensor1.calculate_indices());
          |                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 note: in template argument for type ‘long unsigned int’
       61 |     auto sris_tensor1 = save_recreated_index_sequence<0, tensor1.indices_amount-2, t1_skipPos, tensor1.indices_amount, DIM3>(tensor1.calculate_indices());
          |                                                                                                ~~~~~~~~^~~~~~~~~~~~~~
error: unable to deduce ‘auto’ from ‘sris_tensor1’
       63 |     return sris_tensor1;
          |            ^~~~~~~~~~~~
 In function ‘int main()’:
error: ‘constexpr const void contract’ has incomplete type
      162 |     constexpr auto contract = contraction<0,0>(tensor1, tensor2);
          |                    ^~~~~~~~

1 Ответ

7 голосов
/ 21 января 2020

Вам нужно передать tensor1 в качестве аргумента шаблона, если вы хотите использовать его в контексте, который требует константного выражения. В настоящее время это (C ++ 17) возможно только для справки:

template<std::size_t t1_skipPos, std::size_t t2_skipPos, auto& tensor1, auto& tensor2>
constexpr auto contraction(){

    auto sris_tensor1 = save_recreated_index_sequence<0, tensor1.indices_amount-2, 
         t1_skipPos, tensor1.indices_amount, DIM3>(tensor1.calculate_indices());

    return sris_tensor1;

}

//...

constexpr auto contract = contraction<0, 0, tensor1, tensor2>();

Однако для этого также необходимо объявить tensor1 и tensor2 как static, чтобы они имели связь. В противном случае они не могут быть использованы в качестве аргумента шаблона, и это делает функцию непригодной для использования с переменными, отличными от constexpr.

Обратите внимание, что C ++ 20 добавляет параметры шаблона нетипичного типа класса, которые могут ссылаться, и следовательно, также требование связывания, ненужное (с использованием auto вместо auto&), но это не относится к вашему классу в состоянии current черновика C ++ 20, который требует всех non-stati c члены типа публикуемого типа c. Это требование было недавно изменено, поэтому в текущих версиях компилятора могут быть реализованы менее строгие требования предыдущей черновой версии при использовании -std=c++2a, в котором ваш класс был бы допустимым параметром шаблона нетипизированного типа.

Вы не можете использовать параметры функции в контексте, который требует постоянного выражения. Тот факт, что этот контекст появляется в другой оценке константного выражения, не имеет значения. Функция constexpr всегда должна быть допустимой функцией времени выполнения.


В указанном c случае показанного кода вы можете вместо этого сделать indices_amount static членом класса и получить к нему доступ через тип, чтобы состояние параметров функции никогда не использовалось в контексте константного выражения:

static constexpr std::size_t indices_amount = std::tuple_size_v<Args...>;

//...

template<std::size_t t1_skipPos, std::size_t t2_skipPos, typename T1, typename T2>
constexpr auto contraction(T1 tensor1, T2 tensor2){

    /*ERROR: tensor1 is not a constant expression*/
    auto sris_tensor1 = save_recreated_index_sequence<0, T1::indices_amount-2, 
         t1_skipPos, T1::indices_amount, DIM3>(tensor1.calculate_indices());

    return sris_tensor1;

}

Также обратите внимание, что, кажется, нет никакого смысла в том, что ваш tensorBase имеет пакет параметров в качестве второго параметра шаблона. Он всегда содержит только один аргумент и не будет работать ни с одним другим числом. Например, std::tuple_size<Args...> работает, только если пакет содержит ровно один элемент. Я предлагаю вам удалить все ..., относящиеся к Args в этом классе.

...