2015-03-29 29 views
6

Ich versuchte, Logger mit C++ 11 Variadic Vorlagen zu tun, aber es funktioniert nicht für std::endl, weil std::endl Vorlage Funktion ist und der Compilator weiß nicht, welche Spezialisierung von std::endl auszuwählen. Gibt es einen Weg, wie ich zwingen kann, immer std::endl<char, std::char_traits<char>> auszuwählen? Wenn möglich, möchte ich direkt std :: endl verwenden.C++ 11 Variadische Vorlagen und Std :: Endl

EDIT: es sieht aus wie es derzeit nicht möglich, mit C++ 11 und und beste Weg ist, #define zu verwenden oder was vsoftco beantwortet.

#include <iostream> 
#include <string> 

class Logger { 

public: 

    template<typename T> 
    void log(T val); 

    template <typename T, typename ...Args> 
    void log(T val, Args... args); 

}; 

// explicit specialization not working 
template<> 
void Logger::log(std::basic_ostream<char, std::char_traits<char>> (*modifier) (std::basic_ostream<char, std::char_traits<char>>)) { 

    std::cout << modifier; 

} 

template<typename T> 
void Logger::log(T val) { 

    std::cout << val; 

} 

template<typename T, typename ...Args> 
void Logger::log(T val, Args... args) { 

    log(val); 
    log(args...); 

} 

int main(int argc, char* argv[]) 
{ 
    Logger log; 

    log.log("Nazdar ", "bazar ", "cau", std::endl, "kik"); // ERROR: cannot determine which instance of function template "std::endl" is intended 
    log.log("Nazdar ", "bazar ", "cau", std::endl<char, std::char_traits<char>>, "kik"); 

    std::cin.get(); 

    return 0; 
} 
+0

@vsoftco: 'std :: flush' hat das gleiche Problem wie' std :: endl '. –

+0

@vsoftco: dass die Verwendung wird nicht funktionieren Ursache 'std :: endl' ist kein Typ, es ist Template-Funktion – Krab

+0

@Krab, Entschuldigung für die Verwirrung dieser ganzen Sache, ja, Sie sind absolut richtig. – vsoftco

Antwort

2

kam ich mit diesem nach oben, im Grunde std::endl über eine benutzerdefinierte Wrapper my_endl Mitnahmen Standard Template-Parameter neu zu definieren. Nicht die eleganteste, aber es macht den Job. Natürlich sollte man für mehr solche Manipulatoren einen spezialisierten Wrapper schreiben, aber ich denke, selbst das kann durch eine cleverere Implementierung irgendwie möglich sein.

#include <iostream> 
#include <string> 
#include <type_traits> 

class Logger { 

public: 

    template<typename T> 
    void log(T val); 

    template <typename T, typename ...Args> 
    void log(T val, Args... args); 
}; 

template<typename T> 
void Logger::log(T val) { 
    std::cout << val; 
} 

template<typename T, typename ...Args> 
void Logger::log(T val, Args... args) { 

    log(val); 
    log(args...); 

} 

template< class CharT = char, class Traits = std::char_traits<CharT> > 
inline std::basic_ostream<CharT, Traits>& my_endl(std::basic_ostream<CharT, Traits>& os) 
{ 
    return std::endl(os); 
} 

// or, use the excellent (and better) suggestion by 0x499..., 
// auto manip = std::endl<char, std::char_traits<char>>; 
// log.log(..., manip) 


int main(int argc, char* argv[]) 
{ 
    Logger log; 

    log.log("Nazdar ", "bazar ", "cau", my_endl<>, "kik"); // ERROR: cannot determine which instance of function template "std::endl" is intended 
    log.log("Nazdar ", "bazar ", "cau", my_endl<>, "kik"); 

    std::cin.get(); 

    return 0; 
} 
+0

möchte nur erwähnen, dass @ 0x499 ... Antwort ist eleganter und etwas besser, da es die Umleitung eines zusätzlichen Funktionsaufrufs vermeidet (natürlich kann mine inline machen, aber Sie sollten wirklich 'auto' in diesem Fall verwenden) . – vsoftco

+0

@i wollte eigentlich das 'std :: endl' verwenden, aber wahrscheinlich ist es nicht möglich. In diesem Fall wird '# define' vielleicht der bessere Weg sein, weil er keinen Speicherplatz zur Verfügung stellt. – Krab

+0

@Krab yeah, ich glaube nicht, dass es möglich ist (obwohl ich niemals sage nie), 'std :: endl' zu verwenden. Zumindest kann ich nicht sehen, wie es geht ... – vsoftco

5

Eine einfachere Möglichkeit, das gleiche Ziel zu erreichen:

// global or class member 
enum MyEndl { my_endl }; 

// class member function 
void log(MyEndl x) { std::cout << std::endl; } 

Nutzung:

log.log("Nazdar ", "bazar ", "cau", my_endl, "kik"); 
+0

das ist auch ordentlich! +1 Aber was ist mit dem Senden von "0" zu "log.log (...)"? Sie verwenden keine 'enum-Klasse', erhalten Sie keine Mehrdeutigkeit? Ich meine, Sie werden nicht "0" anzeigen, aber die "enum" wird eine bessere Übereinstimmung sein. Ich ziehe die +1 zurück. – vsoftco

+0

@vsoftco Ich bekomme keine Mehrdeutigkeit beim Kompilieren, und es wählt die Template-Version für '0' aus (altho nicht sicher von den genauen Regeln) –

+0

Nein, ich denke das' Enum 'wird eine bessere Übereinstimmung sein, aber was, wenn Sie '0' anzeigen möchten? Ihre Lösung muss "0" anstelle der Ganzzahl "0" verwenden. Natürlich können Sie eine verrückte unwahrscheinliche Zahl wie '-18947618723' als Anfang des Enums verwenden. – vsoftco

Verwandte Themen