Rekursive Templatefunktion



  • @Miq sagte in Rekursive Templatefunktion:

    Es gibt ja std::is_reference, aber wie verknüpfe ich das mit dem !std::is_pointer?

    mit UND?



  • Ehm, ja, prinzipiell wohl std::is_reference && !std::is_pointer aber ich komme mit den ganzen < > durcheinander... 😟
    Und dar allererste Parameter darf ja ein rvalue sein.



  • Args& statt Args&& und das std::forward weglassen. Am enable_if brauchst du dazu nichts ändern.



  • Es wäre aber vermutlich schlauer den verschiedenen get Funktionen einfach andere Namen zu verpassen.



  • Also z.B. einfach so:

    template <typename T>
    void get_one_impl(uint16_t& index, T& retval) {
      uint16_t sz = sizeof(retval);    // Size of value to be read
    
      retval = 0;                      // return value
    
      // Will it fit?
      if (index <= MM_data.size() - sz) {
        // Yes. Copy it MSB first
        while (sz) {
          sz--;
          retval <<= 8;
          retval |= MM_data[index++];
        }
      }
    }
    
    template <typename... Ts>
    uint16_t get(uint16_t index, Ts&... retvals) {
        (get_one_impl(index, retvals), ...);
        return index;
    }
    


  • @hustbaer sagte in Rekursive Templatefunktion:

    Args& statt Args&& und das std::forward weglassen. Am enable_if brauchst du dazu nichts ändern.

    Nö, ich glaube nicht, denn genau das war ja die Lösung für das ältere Problem - siehe oben in diesem Thread.

    Und mit unterschiedlich benannten Funktionen geht das natürlich, ich habe aber einfach aus Erkenntnisgründen vor, das alles per overloading zu machen. Wenn's nicht geht, gut, aber so schnell möchte ich das nicht aufgeben 😉

    [Update] Aber Du hast mich auf eine andere Idee gebracht. Ich muss mal versuchen, die innere Funktion mit anderem Namen protected zu machen und den Einfachfall uint16_t get(uint16_t index, T&) mit der Templatefunktion mit abzudecken.



  • @Miq sagte in Rekursive Templatefunktion:

    Nö, ich glaube nicht, denn genau das war ja die Lösung für das ältere Problem - siehe oben in diesem Thread.

    Nö. In deinem ursprünglichen Code hattest du Args und nicht Args&.

    Und mit unterschiedlich benannten Funktionen geht das natürlich, ich habe aber einfach aus Erkenntnisgründen vor, das alles per overloading zu machen. Wenn's nicht geht, gut, aber so schnell möchte ich das nicht aufgeben

    Natürlich geht es. Aber wozu?



  • @hustbaer sagte in Rekursive Templatefunktion:

    Nö. In deinem ursprünglichen Code hattest du Args und nicht Args&.

    Stimmt, hast Recht! 👍



  • So geht es:

    // getOne() - read a MSB-first value starting at byte index. Returns updated index
    template <typename T> 
    uint16_t getOne(uint16_t index, T& retval) {
      uint16_t sz = sizeof(retval);    // Size of value to be read
    
      retval = 0;                      // return value
    
      // Will it fit?
      if (index <= MM_data.size() - sz) {
        // Yes. Copy it MSB first
        while (sz) {
          sz--;
          retval <<= 8;
          retval |= MM_data[index++];
        }
      }
      return index;
    }
    
    // Recursion termination helper
    uint16_t get(uint16_t index) { return index; }
    
    // Template function to extend get(index, A&) to get(index, A&, B&, C&, ...)
    template <class T, class... Args>
    typename std::enable_if<!std::is_pointer<T>::value, uint16_t>::type
    get(uint16_t index, T& v, Args&... args) {
      uint16_t pos = getOne(index, v);
      return get(pos, args...);
    }
    

    Ich brauche aber den Einzeiler zum Beenden der Rekursion, weil leider ein leeres Pack immer noch ein Pack ist.

    Danke schön @hustbaer , Deine Anregung hat mich weiter gebracht! 👍



  • Oder du verwendest eben einfach ne Fold-Expression statt der Rekursion. Siehe https://www.c-plusplus.net/forum/topic/352441/rekursive-templatefunktion/10

    if constexpr ginge auch:

    template <class T, class... Args>
    typename std::enable_if<!std::is_pointer<T>::value, uint16_t>::type
    get(uint16_t index, T& v, Args&... args) {
      uint16_t pos = getOne(index, v);
      if constexpr (sizeof...(Args) > 0)
        return get(pos, args...);
      else
        return pos;
    }
    

    Aber wozu kompliziert wenn's mit Fold-Expression noch viel einfacher geht? Macht auch weniger Template-Bloat.


Log in to reply