diff --git a/include/aidge/backend/TensorImpl.hpp b/include/aidge/backend/TensorImpl.hpp
index bc33616a5c23b92344439574f3e3b3f107d1ac6e..1e5c49baf60adf2476cc060b984c371fb4b3e6eb 100644
--- a/include/aidge/backend/TensorImpl.hpp
+++ b/include/aidge/backend/TensorImpl.hpp
@@ -67,18 +67,18 @@ private:
 class TensorImpl {
 public:
     TensorImpl() = delete;
-    TensorImpl(const char *backend, int device = 0) : mBackend(backend), mDevice(device){};
+    TensorImpl(const char *backend, DeviceIdx_t device = 0) : mBackend(backend), mDevice(device){};
 
     /**
      * Return the (backend, device) pair for this implementation.
     */
-    std::pair<std::string, int> device() const { return std::make_pair(mBackend, mDevice); }
+    std::pair<std::string, DeviceIdx_t> device() const { return std::make_pair(mBackend, mDevice); }
 
     /**
      * Set the device ID for current backend.
      * @param device New device ID on current backend.
     */
-    virtual void setDevice(int device) = 0;
+    virtual void setDevice(DeviceIdx_t device) = 0;
 
     /**
      * Copy data from the same device.
@@ -102,7 +102,7 @@ public:
      * @param src Pointer on current implementation backend.
      * @param length Number of elements to copy.
     */
-    virtual void copyFromDevice(const void *src, NbElts_t length, const std::pair<std::string, int>& device) = 0;
+    virtual void copyFromDevice(const void *src, NbElts_t length, const std::pair<std::string, DeviceIdx_t>& device) = 0;
 
     /**
      * Copy data from host.
@@ -121,21 +121,18 @@ public:
     /**
      * Return the raw device pointer.
      * The raw pointer is garanteed to be valid only on the *same* device.
+     * @param offset Offset, in number of elements.
     */
-    virtual void* rawPtr() = 0;
-    virtual const void* rawPtr() const = 0;
+    virtual void* rawPtr(NbElts_t offset = 0) = 0;
+    virtual const void* rawPtr(NbElts_t offset = 0) const = 0;
 
     /**
      * Return the host pointer.
      * If the implementation does not have a valid host pointer, nullptr is returned.
+     * @param offset Offset, in number of elements.
     */
-    virtual void* hostPtr() { return nullptr; };
-    virtual const void* hostPtr() const { return nullptr; };
-
-    /**
-     * Get the device pointer with an offset (in number of elements).
-    */
-    virtual void* getRawPtr(NbElts_t idx) = 0;
+    virtual void* hostPtr(NbElts_t /*offset*/ = 0) { return nullptr; };
+    virtual const void* hostPtr(NbElts_t /*offset*/ = 0) const { return nullptr; };
 
     /**
      * Sets the device pointer. The previously owned data is deleted.
diff --git a/include/aidge/data/Tensor.hpp b/include/aidge/data/Tensor.hpp
index 3d518026f3f5266b81da5aa9ab65efc02c39a902..c1458df042295b6740f6faec131afe8ff1b34a04 100644
--- a/include/aidge/data/Tensor.hpp
+++ b/include/aidge/data/Tensor.hpp
@@ -228,7 +228,7 @@ class Tensor : public Data,
      * @param copyFrom If true (default), move data from previous backend/device
      * to the new one. Previous data is lost otherwise.
      */
-    inline void setBackend(const std::string &name, int device = 0, bool copyFrom = true) {
+    inline void setBackend(const std::string &name, DeviceIdx_t device = 0, bool copyFrom = true) {
         if (mImpl) {
             if (mImpl->device() != std::make_pair(name, device)) {
                 // Backend change: create new impl, copy from old to new and replace
@@ -363,23 +363,11 @@ class Tensor : public Data,
      */
     bool empty() const { return mDims.empty(); }
 
-    template <typename expectedType>
-    expectedType& get(std::size_t idx){
-        // TODO : add assert expected Type compatible with datatype
-        // TODO : add assert idx < Size
-        return *reinterpret_cast<expectedType *>(mImpl->getRawPtr(idx));
-    }
-
     template <typename expectedType>
     const expectedType& get(std::size_t idx) const {
-        // TODO : add assert expected Type compatible with datatype
-        // TODO : add assert idx < Size
-        return *reinterpret_cast<expectedType *>(mImpl->getRawPtr(idx));
-    }
-
-    template <typename expectedType>
-    expectedType& get(std::vector<std::size_t> coordIdx){
-        return get<expectedType>(getIdx(coordIdx));
+        AIDGE_ASSERT(NativeType<expectedType>::type == mDataType, "wrong data type");
+        AIDGE_ASSERT(idx < mSize, "idx out of range");
+        return *reinterpret_cast<expectedType *>(mImpl->hostPtr(idx));
     }
 
     template <typename expectedType>
@@ -389,9 +377,9 @@ class Tensor : public Data,
 
     template <typename expectedType>
     void set(std::size_t idx, expectedType value){
-        // TODO : add assert expected Type compatible with datatype
-        // TODO : add assert idx < Size
-        expectedType* dataPtr = static_cast<expectedType*>(mImpl->getRawPtr(idx));
+        AIDGE_ASSERT(NativeType<expectedType>::type == mDataType, "wrong data type");
+        AIDGE_ASSERT(idx < mSize, "idx out of range");
+        expectedType* dataPtr = static_cast<expectedType*>(mImpl->hostPtr(idx));
         *dataPtr = value;
     }
 
@@ -610,8 +598,8 @@ class Tensor : public Data,
      * @param device The desired device.
      * @return Reference to either itself or to fallback.
     */
-    Tensor& refFrom(std::shared_ptr<Tensor>& fallback, const std::string &backend, int device = 0);
-    const Tensor& refFrom(std::shared_ptr<Tensor>& fallback, const std::string &backend, int device = 0) const;
+    Tensor& refFrom(std::shared_ptr<Tensor>& fallback, const std::string &backend, DeviceIdx_t device = 0);
+    const Tensor& refFrom(std::shared_ptr<Tensor>& fallback, const std::string &backend, DeviceIdx_t device = 0) const;
 
     /**
      * Return a reference to a Tensor on desired data type and backend/device:
@@ -628,7 +616,7 @@ class Tensor : public Data,
      * @param device The desired device.
      * @return Reference to either itself or to fallback.
     */
-    Tensor& refCastFrom(std::shared_ptr<Tensor>& fallback, const Aidge::DataType& dt, const std::string &backend, int device = 0) {
+    Tensor& refCastFrom(std::shared_ptr<Tensor>& fallback, const Aidge::DataType& dt, const std::string &backend, DeviceIdx_t device = 0) {
         // First refFrom, to ensure that fallback, if required, is also on desired device
         return refFrom(fallback, backend, device).refCast(fallback, dt);
     }
diff --git a/include/aidge/graph/GraphView.hpp b/include/aidge/graph/GraphView.hpp
index e22bde7c6a2fee047ffe6fb0b570388d1ad67d7d..539e8a03ea26cf9f9d3d9696add19779f97278df 100644
--- a/include/aidge/graph/GraphView.hpp
+++ b/include/aidge/graph/GraphView.hpp
@@ -203,7 +203,7 @@ public:
      * If not, add a Transpose Operator.
      * 4 - Propagate Tensor dimensions through the consecutive Operators.
      */
-    void compile(const std::string& backend, const Aidge::DataType datatype, int device = 0);
+    void compile(const std::string& backend, const Aidge::DataType datatype, DeviceIdx_t device = 0);
 
     /**
      * @brief Compute dimensions of input/output Tensors for each Operator of the
@@ -212,7 +212,7 @@ public:
     void forwardDims();
 
     /** @brief Set the same backend for each Operator of the GraphView object's Nodes. */
-    void setBackend(const std::string &backend, int device = 0);
+    void setBackend(const std::string &backend, DeviceIdx_t device = 0);
     /** @brief Set the same backend for each Operator of the GraphView object's Nodes. */
     void setDataType(const DataType &datatype);
 
diff --git a/include/aidge/operator/Add.hpp b/include/aidge/operator/Add.hpp
index 3ecedf72756a43ed011ac7063dddedef2e81dae2..9aed8299a67ab719141b6fe199ebf3f52fb7d387 100644
--- a/include/aidge/operator/Add.hpp
+++ b/include/aidge/operator/Add.hpp
@@ -76,7 +76,7 @@ public:
     // }
 
 
-    void setBackend(const std::string& name, int device = 0) override {
+    void setBackend(const std::string& name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<Add_Op>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
     }
diff --git a/include/aidge/operator/AvgPooling.hpp b/include/aidge/operator/AvgPooling.hpp
index 2d550d1734f7d68d9061dd67d9b89984e70c8509..6c0a64dc8d4b563976183b789bf4a09aee75a664 100644
--- a/include/aidge/operator/AvgPooling.hpp
+++ b/include/aidge/operator/AvgPooling.hpp
@@ -134,7 +134,7 @@ public:
     }
 
 
-    void setBackend(const std::string &name, int device = 0) override {
+    void setBackend(const std::string &name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<AvgPooling_Op<DIM>>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
     }
diff --git a/include/aidge/operator/BatchNorm.hpp b/include/aidge/operator/BatchNorm.hpp
index 055c1b308470e3fe65693138c8e1e8f72ea62d5e..d3e0fceabd40d0ebf3c4521bd3010e1d1538b89f 100644
--- a/include/aidge/operator/BatchNorm.hpp
+++ b/include/aidge/operator/BatchNorm.hpp
@@ -94,7 +94,7 @@ public:
         }
     }
 
-    void setBackend(const std::string &name, int device = 0) override {
+    void setBackend(const std::string &name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<BatchNorm_Op<DIM>>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
 
diff --git a/include/aidge/operator/Cast.hpp b/include/aidge/operator/Cast.hpp
index 38fb0b1ffcbb243658cb8d57af04e97a7179f5f2..7cc3985674219daf087381049d3a845299b3e250 100644
--- a/include/aidge/operator/Cast.hpp
+++ b/include/aidge/operator/Cast.hpp
@@ -28,7 +28,7 @@ namespace Aidge {
 class Cast_Op : public OperatorTensor,
     public Registrable<Cast_Op, std::string, std::unique_ptr<OperatorImpl>(const Cast_Op&)> {
 public:
-    static constexpr const char* Type = "Cast";
+    static const std::string Type;
 
     Cast_Op() : OperatorTensor(Type, 1, 0, 1) {}
 
@@ -50,7 +50,10 @@ public:
         return std::make_shared<Cast_Op>(*this);
     }
 
-    void setBackend(const std::string& name, int device = 0) override {
+    void setBackend(const std::string& name, DeviceIdx_t device = 0) override {
+        if (Registrar<Cast_Op>::exists({name})) {
+            mImpl = Registrar<Cast_Op>::create({name})(*this);
+        }
         mOutputs[0]->setBackend(name, device);
     }
 
diff --git a/include/aidge/operator/Concat.hpp b/include/aidge/operator/Concat.hpp
index ca91172f65f5509cf24f32ac463f96474b292e3e..06cc468bd7266bbcfeb6802f274c536ec09867fc 100644
--- a/include/aidge/operator/Concat.hpp
+++ b/include/aidge/operator/Concat.hpp
@@ -101,7 +101,7 @@ public:
         }
     }
 
-    void setBackend(const std::string& name, int device = 0) override {
+    void setBackend(const std::string& name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<Concat_Op>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
     }
diff --git a/include/aidge/operator/Conv.hpp b/include/aidge/operator/Conv.hpp
index cbed859d122722c62e6b73af510b3f0c83ead749..6585c2d306b1a36544a36681ef7bd4b2e9d1b9b8 100644
--- a/include/aidge/operator/Conv.hpp
+++ b/include/aidge/operator/Conv.hpp
@@ -171,7 +171,7 @@ std::vector<std::pair<std::size_t, std::vector<DimSize_t>>> computeReceptiveFiel
         AIDGE_THROW_OR_ABORT(std::runtime_error, "Given outputDim out of range or output dim not forwarded yet.");
     }
 
-    void setBackend(const std::string &name, int device = 0) override {
+    void setBackend(const std::string &name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<Conv_Op<DIM>>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
 
diff --git a/include/aidge/operator/ConvDepthWise.hpp b/include/aidge/operator/ConvDepthWise.hpp
index c9f1727183f63ba94ac404606e9d048414477954..839a0ec793139a343d2f279dba283df9a81e88b2 100644
--- a/include/aidge/operator/ConvDepthWise.hpp
+++ b/include/aidge/operator/ConvDepthWise.hpp
@@ -165,7 +165,7 @@ public:
         AIDGE_THROW_OR_ABORT(std::runtime_error, "Given outputDim out of range or output dim not forwarded yet.");
     }
 
-    void setBackend(const std::string &name, int device = 0) override {
+    void setBackend(const std::string &name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<ConvDepthWise_Op<DIM>>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
 
diff --git a/include/aidge/operator/Div.hpp b/include/aidge/operator/Div.hpp
index 323f3058bdf9e6311bbfdf93f6675ee651efa27a..94b755e0fdb0f76d54cd4f046fb8b08dda05b6b2 100644
--- a/include/aidge/operator/Div.hpp
+++ b/include/aidge/operator/Div.hpp
@@ -54,7 +54,7 @@ public:
     void computeOutputDims() override final;
 
 
-    void setBackend(const std::string& name, int device = 0) override {
+    void setBackend(const std::string& name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<Div_Op>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
     }
diff --git a/include/aidge/operator/FC.hpp b/include/aidge/operator/FC.hpp
index 52297525ec92063d7be6123b1853ff01af4ddbd5..36ff7106cd3287ea45c743aace16cbc79f63820b 100644
--- a/include/aidge/operator/FC.hpp
+++ b/include/aidge/operator/FC.hpp
@@ -95,7 +95,7 @@ public:
     }
 
 
-    void setBackend(const std::string& name, int device = 0) override {
+    void setBackend(const std::string& name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<FC_Op>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
 
diff --git a/include/aidge/operator/GenericOperator.hpp b/include/aidge/operator/GenericOperator.hpp
index 6adf031051b554878fc165c59f2aff0c81e35a9a..c966b5f5c1bb4914f3e46f96493da87a6707b1ff 100644
--- a/include/aidge/operator/GenericOperator.hpp
+++ b/include/aidge/operator/GenericOperator.hpp
@@ -97,7 +97,7 @@ public:
 
     ~GenericOperator_Op() = default;
 
-    void setBackend(const std::string & /*name*/, int /*device*/ = 0) override { printf("setBackend: not available yet.\n"); }
+    void setBackend(const std::string & /*name*/, DeviceIdx_t /*device*/ = 0) override { printf("setBackend: not available yet.\n"); }
     void setDataType(const DataType& /*datatype*/) const override { printf("setDataType: not available yet.\n"); }
     void forward() override final {
         if(mImpl){
diff --git a/include/aidge/operator/Identity.hpp b/include/aidge/operator/Identity.hpp
index 50c5ef941ac07ea79c7d74aead642b0790907d96..7348fa10a96c55914bae68983b5e3bd4a9c40b12 100644
--- a/include/aidge/operator/Identity.hpp
+++ b/include/aidge/operator/Identity.hpp
@@ -103,7 +103,7 @@ public:
         }
         return mInputs[outputIdx];
     }
-    void setBackend(const std::string& /*name*/, int /*device*/ = 0) override final {
+    void setBackend(const std::string& /*name*/, DeviceIdx_t /*device*/ = 0) override final {
         // setBackend do nothing, Identity node has no backend it just pass the same Tensor
     }
     void setDataType(const DataType& /*dataType*/) const override final {
diff --git a/include/aidge/operator/LeakyReLU.hpp b/include/aidge/operator/LeakyReLU.hpp
index b8e95b07d81b68aa865e55cba55c7c49c061f63b..5976f1d88d70ae7fb716f4038e57da95242c3551 100644
--- a/include/aidge/operator/LeakyReLU.hpp
+++ b/include/aidge/operator/LeakyReLU.hpp
@@ -67,7 +67,7 @@ public:
 
 
 
-    void setBackend(const std::string& name, int device = 0) override {
+    void setBackend(const std::string& name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<LeakyReLU_Op>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
     }
diff --git a/include/aidge/operator/MatMul.hpp b/include/aidge/operator/MatMul.hpp
index 10488ed99a049c0d90169bc6f9c848fe9081498f..3d80193be3f669b00e5a138470269e52d0715780 100644
--- a/include/aidge/operator/MatMul.hpp
+++ b/include/aidge/operator/MatMul.hpp
@@ -83,7 +83,7 @@ public:
     }
 
 
-    void setBackend(const std::string& name, int device = 0) override {
+    void setBackend(const std::string& name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<MatMul_Op>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
     }
diff --git a/include/aidge/operator/MaxPooling.hpp b/include/aidge/operator/MaxPooling.hpp
index 1cfa29b949ee4d2ebf5293069b553a5f829ffb39..467a69d73c98a21c85e956acf42536e197833cbd 100644
--- a/include/aidge/operator/MaxPooling.hpp
+++ b/include/aidge/operator/MaxPooling.hpp
@@ -104,7 +104,7 @@ public:
     }
 
 
-    void setBackend(const std::string &name, int device = 0) override {
+    void setBackend(const std::string &name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<MaxPooling_Op<DIM>>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
     }
diff --git a/include/aidge/operator/MetaOperator.hpp b/include/aidge/operator/MetaOperator.hpp
index ba1ed5f16043364a14993420868a1974f5785598..827793a1b9713b0fcf23b26f6ce9db43c43d8026 100644
--- a/include/aidge/operator/MetaOperator.hpp
+++ b/include/aidge/operator/MetaOperator.hpp
@@ -70,7 +70,7 @@ public:
     }
 
 
-    void setBackend(const std::string &name, int device = 0) override {
+    void setBackend(const std::string &name, DeviceIdx_t device = 0) override {
         if (Registrar<MetaOperator_Op>::exists({name, type()})) {
             // A custom implementation exists for this meta operator
             mImpl = Registrar<MetaOperator_Op>::create({name, type()})(*this);
diff --git a/include/aidge/operator/Move.hpp b/include/aidge/operator/Move.hpp
index be7f8922ecbea3356e55216f2381da360e4e8f39..62fb9897384673c695895b54557b4cf637aa2447 100644
--- a/include/aidge/operator/Move.hpp
+++ b/include/aidge/operator/Move.hpp
@@ -28,7 +28,7 @@ namespace Aidge {
 class Move_Op : public OperatorTensor,
     public Registrable<Move_Op, std::tuple<std::string, std::string>, std::unique_ptr<OperatorImpl>(const Move_Op&)> {
 public:
-    static constexpr const char* Type = "Move";
+    static const std::string Type;
 
     Move_Op() : OperatorTensor(Type, 1, 0, 1) {}
 
@@ -50,7 +50,7 @@ public:
         return std::make_shared<Move_Op>(*this);
     }
 
-    void setBackend(const std::string& name, int device = 0) override {
+    void setBackend(const std::string& name, DeviceIdx_t device = 0) override {
         if (mInputs[0]->getImpl() && Registrar<Move_Op>::exists({mInputs[0]->getImpl()->backend(), name})) {
             mImpl = Registrar<Move_Op>::create({mInputs[0]->getImpl()->backend(), name})(*this);
         }
diff --git a/include/aidge/operator/Mul.hpp b/include/aidge/operator/Mul.hpp
index 33011ed1e25d5a1e78326f6ccff161c9299ee9b4..78b2fa5f98c9dae66ae291769f2de08d7805a738 100644
--- a/include/aidge/operator/Mul.hpp
+++ b/include/aidge/operator/Mul.hpp
@@ -56,7 +56,7 @@ public:
 
     void computeOutputDims() override final;
 
-    void setBackend(const std::string& name, int device = 0) override {
+    void setBackend(const std::string& name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<Mul_Op>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
     }
diff --git a/include/aidge/operator/Operator.hpp b/include/aidge/operator/Operator.hpp
index ffd627ee7eca17c4870dc914c3ff53e2a5a24ec3..715b6a0282a5acc678afd725e553f91ea02281b8 100644
--- a/include/aidge/operator/Operator.hpp
+++ b/include/aidge/operator/Operator.hpp
@@ -105,7 +105,7 @@ public:
 //        IMPLEMENTATION
 ///////////////////////////////////////////////////////
 
-    virtual void setBackend(const std::string& name, int device = 0) = 0;
+    virtual void setBackend(const std::string& name, DeviceIdx_t device = 0) = 0;
     virtual void setDataType(const DataType& dataType) const = 0;
 
     /**
diff --git a/include/aidge/operator/Pad.hpp b/include/aidge/operator/Pad.hpp
index 11cbc34093d3d4649e1b746f370602ffa9c5712f..56245dd2dfd62d4dc765de6e3d43b08c144cc62b 100644
--- a/include/aidge/operator/Pad.hpp
+++ b/include/aidge/operator/Pad.hpp
@@ -97,7 +97,7 @@ public:
         }
     }
 
-    void setBackend(const std::string &name, int device = 0) override {
+    void setBackend(const std::string &name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<Pad_Op<DIM>>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
     }
diff --git a/include/aidge/operator/Pow.hpp b/include/aidge/operator/Pow.hpp
index d89776d2172fe25689593c2036929a746b974376..d498cacc7c5b2ddc3269f3ebc77707aead8eb52d 100644
--- a/include/aidge/operator/Pow.hpp
+++ b/include/aidge/operator/Pow.hpp
@@ -54,7 +54,7 @@ public:
     void computeOutputDims() override final;
 
 
-    void setBackend(const std::string& name, int device = 0) override {
+    void setBackend(const std::string& name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<Pow_Op>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
     }
diff --git a/include/aidge/operator/Producer.hpp b/include/aidge/operator/Producer.hpp
index 51ce579f6b7e1a9c691bb021d88b5bd77d975459..ee00ead696efe623a4e051994f470a38397777ec 100644
--- a/include/aidge/operator/Producer.hpp
+++ b/include/aidge/operator/Producer.hpp
@@ -76,7 +76,7 @@ public:
 
     inline const std::vector<DimSize_t> dims() const noexcept { return mOutputs[0]->dims(); }
 
-    void setBackend(const std::string& name, int device = 0) override {
+    void setBackend(const std::string& name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<Producer_Op>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
     }
diff --git a/include/aidge/operator/ReLU.hpp b/include/aidge/operator/ReLU.hpp
index d6a8c2b6189023f3ca03c85c892e74724eab36d0..0bb7cdffe421b973ae7c86b4569e7464b3cf6da4 100644
--- a/include/aidge/operator/ReLU.hpp
+++ b/include/aidge/operator/ReLU.hpp
@@ -51,7 +51,7 @@ public:
     }
 
 
-    void setBackend(const std::string& name, int device = 0) override {
+    void setBackend(const std::string& name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<ReLU_Op>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
     }
diff --git a/include/aidge/operator/Scaling.hpp b/include/aidge/operator/Scaling.hpp
index 0770329065e3a0a15939516181428c8c4b2e7986..54f1d98d2f61d18dd821c9f0a6b574bb52b0c9f0 100644
--- a/include/aidge/operator/Scaling.hpp
+++ b/include/aidge/operator/Scaling.hpp
@@ -66,7 +66,7 @@ public:
         return std::make_shared<Scaling_Op>(*this);
     }
 
-    void setBackend(const std::string& name, int device = 0) override {
+    void setBackend(const std::string& name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<Scaling_Op>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
     }
diff --git a/include/aidge/operator/Slice.hpp b/include/aidge/operator/Slice.hpp
index 95e0c72eb38587221732e8ec357b1c106d468275..15a707b5fddc84207213cd168f811c9dc5507c1f 100644
--- a/include/aidge/operator/Slice.hpp
+++ b/include/aidge/operator/Slice.hpp
@@ -90,7 +90,7 @@ public:
         mOutputs[0]->resize(outputDims);
     }
 
-    void setBackend(const std::string &name, int device = 0) override {
+    void setBackend(const std::string &name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<Slice_Op>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
     }
diff --git a/include/aidge/operator/Softmax.hpp b/include/aidge/operator/Softmax.hpp
index 913b58cb5347aea9f13b46ef28b27cdfae182756..b04d1ebbd0d5b358416fe3a5a67a6cc103fc9a58 100644
--- a/include/aidge/operator/Softmax.hpp
+++ b/include/aidge/operator/Softmax.hpp
@@ -51,7 +51,7 @@ public:
         return std::make_shared<Softmax_Op>(*this);
     }
 
-    void setBackend(const std::string& name, int device = 0) override {
+    void setBackend(const std::string& name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<Softmax_Op>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
     }
diff --git a/include/aidge/operator/Sqrt.hpp b/include/aidge/operator/Sqrt.hpp
index b95cdfe85051f59202f84e76c15103d23c9edb93..32adfdb93db1e9da857f4147efdcfe64bbb34475 100644
--- a/include/aidge/operator/Sqrt.hpp
+++ b/include/aidge/operator/Sqrt.hpp
@@ -56,7 +56,7 @@ public:
         return std::make_shared<Sqrt_Op>(*this);
     }
 
-    void setBackend(const std::string& name, int device = 0) override {
+    void setBackend(const std::string& name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<Sqrt_Op>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
     }
diff --git a/include/aidge/operator/Sub.hpp b/include/aidge/operator/Sub.hpp
index 9b84cf3d28c4e5ce0ed9b84c128ef3c05c1c6f35..ee5efa24dc24ebcd5ad4c45491c968caf691eee9 100644
--- a/include/aidge/operator/Sub.hpp
+++ b/include/aidge/operator/Sub.hpp
@@ -59,7 +59,7 @@ public:
     void computeOutputDims() override final;
 
 
-    void setBackend(const std::string& name, int device = 0) override {
+    void setBackend(const std::string& name, DeviceIdx_t device = 0) override {
         mImpl = Registrar<Sub_Op>::create(name)(*this);
         mOutputs[0]->setBackend(name, device);
     }
diff --git a/include/aidge/utils/Registrar.hpp b/include/aidge/utils/Registrar.hpp
index d2b256582ed2e94bf14d97f3a382f133ad989b1d..66a07eb0ce21354b20f1ca416cc68d26d9bd6280 100644
--- a/include/aidge/utils/Registrar.hpp
+++ b/include/aidge/utils/Registrar.hpp
@@ -54,26 +54,26 @@ struct Registrar {
     typedef typename C::registrar_key registrar_key;
     typedef typename C::registrar_type registrar_type;
 
-    Registrar(const typename C::registrar_key& key, typename C::registrar_type func) {
+    Registrar(const registrar_key& key, registrar_type func) {
         //printf("REGISTRAR: %s\n", key.c_str());
         bool newInsert;
         std::tie(std::ignore, newInsert) = C::registry().insert(std::make_pair(key, func));
         //assert(newInsert && "registrar already exists");
     }
 
-    static bool exists(const typename C::registrar_key& key) {
+    static bool exists(const registrar_key& key) {
         const auto it = C::registry().find(key);
         return (it != C::registry().end());
     }
 
-    static auto create(const typename C::registrar_key& key){
+    static auto create(const registrar_key& key){
         const auto it = C::registry().find(key);
         assert(it != C::registry().end() && "invalid registrar key");
 
         return (*it).second;
     }
-    static std::vector<typename C::registrar_key> getKeys(){
-        std::vector<typename C::registrar_key> keys;
+    static std::vector<registrar_key> getKeys(){
+        std::vector<registrar_key> keys;
         for(auto keyValue : C::registry())
             keys.push_back(keyValue.first);
         return keys;
diff --git a/include/aidge/utils/TensorUtils.hpp b/include/aidge/utils/TensorUtils.hpp
index e4da1e12eb675bc21ea72fd483474883cb8b9a46..1bfe0929bf67bb0c6d3b893f3dbaf6993dcfd6ff 100644
--- a/include/aidge/utils/TensorUtils.hpp
+++ b/include/aidge/utils/TensorUtils.hpp
@@ -33,7 +33,7 @@ namespace Aidge {
  * @return true if both tensor are approximately equal and have the datatype, shape. Else return false
  */
 template <typename T1, typename T2 = T1>
-bool approxEq(const Tensor& t1, const Tensor& t2, float relative, float absolute){
+bool approxEq(const Tensor& t1, const Tensor& t2, float relative = 1e-5f, float absolute = 1e-8f){
     assert(t1.dataType() == NativeType<T1>::type);
     assert(t2.dataType() == NativeType<T2>::type);
     assert(relative >= 0);
diff --git a/include/aidge/utils/Types.h b/include/aidge/utils/Types.h
index d65279f1f4d36498ea7653428332690fc99a5def..b601df1cb8f8fa81cd2339e7eb393f7297e63499 100644
--- a/include/aidge/utils/Types.h
+++ b/include/aidge/utils/Types.h
@@ -24,6 +24,10 @@ namespace Aidge
 ///          Tensor
 //////////////////////////////////////
 
+/// @brief Device index in a given backend
+using DeviceIdx_t = std::uint8_t;
+constexpr DeviceIdx_t MaxDeviceIdx = std::numeric_limits<DeviceIdx_t>::max();
+
 /// @brief Number of elements used for scheduling
 using NbElts_t = std::size_t;
 constexpr NbElts_t MaxElts = std::numeric_limits<NbElts_t>::max();
diff --git a/src/data/Tensor.cpp b/src/data/Tensor.cpp
index 8a950ba2febcfb5b0f22420af0feae40204c5646..da0c626d78dd1cc4452bfc07bf6c6a7f58b8d1e4 100644
--- a/src/data/Tensor.cpp
+++ b/src/data/Tensor.cpp
@@ -107,12 +107,12 @@ const Aidge::Tensor& Aidge::Tensor::refCast(std::shared_ptr<Tensor>& fallback, c
     }
 }
 
-Aidge::Tensor& Aidge::Tensor::refFrom(std::shared_ptr<Tensor>& fallback, const std::string &backend, int device) {
+Aidge::Tensor& Aidge::Tensor::refFrom(std::shared_ptr<Tensor>& fallback, const std::string &backend, DeviceIdx_t device) {
     // Scott Meyers' solution to avoid code duplication
     return const_cast<Tensor&>(static_cast<const Tensor&>(*this).refFrom(fallback, backend, device));
 }
 
-const Aidge::Tensor& Aidge::Tensor::refFrom(std::shared_ptr<Tensor>& fallback, const std::string &backend, int device) const {
+const Aidge::Tensor& Aidge::Tensor::refFrom(std::shared_ptr<Tensor>& fallback, const std::string &backend, DeviceIdx_t device) const {
     AIDGE_ASSERT(getImpl(), "no backend was set for tensor, cannot refFrom() it");
 
     if (std::make_pair(backend, device) == getImpl()->device()) {
diff --git a/src/graph/GraphView.cpp b/src/graph/GraphView.cpp
index 9b788fc5e972c1020994b31d5fc89459d0f4a915..dcfa8275ae01f46f846d24484141dbc87bc86541 100644
--- a/src/graph/GraphView.cpp
+++ b/src/graph/GraphView.cpp
@@ -247,7 +247,7 @@ Aidge::GraphView::inputs(std::string name) const {
   return mNodeRegistry.at(name)->inputs();
 }
 
-void Aidge::GraphView::compile(const std::string& backend, const Aidge::DataType datatype, int device) {
+void Aidge::GraphView::compile(const std::string& backend, const Aidge::DataType datatype, DeviceIdx_t device) {
     // Backend
     // TODO: add Backend attribute to Operator
     setBackend(backend, device);
@@ -319,7 +319,7 @@ void Aidge::GraphView::_forwardDims(std::set<std::shared_ptr<Node>> listNodes) {
     }
 }
 
-void Aidge::GraphView::setBackend(const std::string &backend, int device) {
+void Aidge::GraphView::setBackend(const std::string &backend, DeviceIdx_t device) {
     for (auto node : getNodes()) {
         node->getOperator()->setBackend(backend, device);
     }
diff --git a/src/operator/Cast.cpp b/src/operator/Cast.cpp
index 0ac6d5f5304b62a832f84eaadcb7b6dbfe0a34e0..f09d8eb83c6a6dae6416ffebcc01b22fb479a862 100644
--- a/src/operator/Cast.cpp
+++ b/src/operator/Cast.cpp
@@ -12,6 +12,8 @@
 #include "aidge/backend/OperatorImpl.hpp"
 #include "aidge/operator/Cast.hpp"
 
+const std::string Aidge::Cast_Op::Type = "Cast";
+
 void Aidge::Cast_Op::forward() {
     if (mImpl) {
         mImpl->forward();
diff --git a/src/operator/Move.cpp b/src/operator/Move.cpp
index d828e994d61bb7307a55c120685ac4a2808fc086..d8776e32fca909663bafe3fae3ebf9f5616c69c9 100644
--- a/src/operator/Move.cpp
+++ b/src/operator/Move.cpp
@@ -12,6 +12,8 @@
 #include "aidge/backend/OperatorImpl.hpp"
 #include "aidge/operator/Move.hpp"
 
+const std::string Aidge::Move_Op::Type = "Move";
+
 void Aidge::Move_Op::forward() {
     if (mImpl) {
         mImpl->forward();