templates + rekursion



  • Hi, ich arbeite mich gerade ein bischen in template metaprogramming und die C++11 Features ein. Dabei stoße ich auf folgendes Problem:

    template <size_t N>
    struct n {
        static const size_t value = N;
    };
    
    template <typename...Args>
    constexpr size_t size_of() {
        return sizeof...(Args);
    }
    
    template <typename T, typename...Args>
    typename std::enable_if<(size_of<Args...>() > 0), size_t>::type
    sum() {
        return T::value + sum<Args...>();
    }
    
    template <typename T, typename...Args>
    typename std::enable_if<(size_of<Args...>() == 0), size_t>::type
    sum() {
        return T::value;
    }
    
    int main(int argc, char **argv) {
       sum<n<2>,n<7>>();
    }
    

    gcc 4.8.2 20140206 schrieb:

    /var/projects/mg/src/ffuzz/main.cpp: In instantiation of ‘typename std::enable_if<(size_of<Args ...>() > 0), long unsigned int>::type sum() [with T = n<2ul>; Args = {n<7ul>}; typename std::enable_if<(size_of<Args ...>() > 0), long unsigned int>::type = long unsigned int]’:
    /var/projects/mg/src/ffuzz/main.cpp:38:31: required from here
    /var/projects/mg/src/ffuzz/main.cpp:26:36: error: no matching function for call to ‘sum()’
    return T::value + sum<Args...>();
    ^
    /var/projects/mg/src/ffuzz/main.cpp:26:36: note: candidate is:
    /var/projects/mg/src/ffuzz/main.cpp:25:1: note: template<class T, class ... Args> typename std::enable_if<(size_of<Args ...>() > 0), long unsigned int>::type sum()
    sum() {
    ^
    /var/projects/mg/src/ffuzz/main.cpp:25:1: note: template argument deduction/substitution failed:
    /var/projects/mg/src/ffuzz/main.cpp: In substitution of ‘template<class T, class ... Args> typename std::enable_if<(size_of<Args ...>() > 0), long unsigned int>::type sum() [with T = n<7ul>; Args = {}]’:
    /var/projects/mg/src/ffuzz/main.cpp:26:36: required from ‘typename std::enable_if<(size_of<Args ...>() > 0), long unsigned int>::type sum() [with T = n<2ul>; Args = {n<7ul>}; typename std::enable_if<(size_of<Args ...>() > 0), long unsigned int>::type = long unsigned int]’
    /var/projects/mg/src/ffuzz/main.cpp:38:31: required from here
    /var/projects/mg/src/ffuzz/main.cpp:25:1: error: no type named ‘type’ in ‘struct std::enable_if<false, long unsigned int>’

    Warum scheitert der Compiler beim Rekursionsanker? Ich verstehe gerade nicht, warum hier nicht Variante 2 ausgewählt wird.


  • Mod

    Falsche Reihenfolge bei der Definition. Kompilierst du es mit Clang, gibt er dir auch eine schöne Erklärung.


  • Mod

    Ich verstehe gerade nicht, warum hier nicht Variante 2 ausgewählt wird.

    Ich verstehe nicht, warum sie das sollte.

    §14.6/1 schrieb:

    Three kinds of names can be used within a template definition:
    — The name of the template itself, and names declared within the template itself.
    — Names dependent on a template-parameter (14.6.2).
    — Names from scopes which are visible within the template definition.

    Und sum ist nicht abhängig, weil weder der Name selbst - sum - abhängig ist, noch eines der Argumente für den Funktionsaufruf.

    Übrigens würde das auch mit einem abhängigen Argument nicht funktionieren, weil ADL - grob gesagt - nur auf Funktionsaufrufe ohne explizite Template-Argumente funktioniert (§14.8.1/8).


Anmelden zum Antworten