मैंने ऐसे प्रकार देखे हैं जिनके पास to_string()
फ़ंक्शन है, लेकिन operator<<()
को ओवरलोड नहीं किया है। इसलिए, स्ट्रीम में डालने पर, किसी को << to_string(x)
होना चाहिए जो वर्बोज़ है। मैं सोच रहा हूं कि क्या एक सामान्य कार्य लिखना संभव है कि उपयोगकर्ता operator<<()
समर्थित हैं और << to_string()
पर वापस आते हैं।ऑपरेटर <<() विफल रहता है <<() विफल रहता है
उत्तर
SFINAE overkill है, ADL का उपयोग करें।
चाल सुनिश्चित करें कि एकoperator<<
उपलब्ध है, बनाने के लिए है जरूरी नहीं कि एक प्रकार परिभाषा द्वारा आपूर्ति:
namespace helper {
template<typename T> std::ostream& operator<<(std::ostream& os, T const& t)
{
return os << to_string(t);
}
}
using helper::operator<<;
std::cout << myFoo;
यह चाल आमतौर पर सामान्य कोड जो std::swap<T>
के बीच चयन करने की जरूरत है में प्रयोग किया जाता है और एक विशेष Foo::swap(Foo::Bar&, Foo::Bar&)
।
हां, यह संभव है।
#include <iostream>
#include <sstream>
#include <string>
#include <type_traits>
struct streamy
{
};
std::ostream&
operator<<(std::ostream& os, const streamy& obj)
{
return os << "streamy [" << static_cast<const void *>(&obj) << "]";
}
struct stringy
{
};
std::string
to_string(const stringy& obj)
{
auto oss = std::ostringstream {};
oss << "stringy [" << static_cast<const void *>(&obj) << "]";
return oss.str();
}
template <typename T>
std::enable_if_t
<
std::is_same
<
std::string,
decltype(to_string(std::declval<const T&>()))
>::value,
std::ostream
>&
operator<<(std::ostream& os, const T& obj)
{
return os << to_string(obj);
}
int
main()
{
std::cout << streamy {} << '\n';
std::cout << stringy {} << '\n';
}
सामान्य operator<<
ही उपलब्ध हो सकता है अगर अभिव्यक्ति to_string(obj)
के लिए obj
एक const T&
अच्छी तरह से आपके द्वारा लिखा गया है और प्रकार std::string
का एक परिणाम है। जैसा कि आप पहले से ही अपनी टिप्पणी में अनुमान लगा चुके हैं, यह वास्तव में काम पर SFINAE है। यदि decltype
अभिव्यक्ति अच्छी तरह से गठित नहीं है, तो हमें प्रतिस्थापन विफलता मिल जाएगी और अधिभार गायब हो जाएगा।
हालांकि, यह आपको अस्पष्ट ओवरलोड के साथ परेशानी में डाल देगा। कम से कम, अपने फॉलबैक operator<<
को अपने namespace
में डालें और केवल आवश्यकता होने पर इसे using
घोषणा के माध्यम से स्थानीय रूप से खींचें। मुझे लगता है कि आप एक नामित फ़ंक्शन लिखने से बेहतर होंगे जो वही काम करता है।
namespace detail
{
enum class out_methods { directly, to_string, member_str, not_at_all };
template <out_methods> struct tag {};
template <typename T>
void
out(std::ostream& os, const T& arg, const tag<out_methods::directly>)
{
os << arg;
}
template <typename T>
void
out(std::ostream& os, const T& arg, const tag<out_methods::to_string>)
{
os << to_string(arg);
}
template <typename T>
void
out(std::ostream& os, const T& arg, const tag<out_methods::member_str>)
{
os << arg.str();
}
template <typename T>
void
out(std::ostream&, const T&, const tag<out_methods::not_at_all>)
{
// This function will never be called but we provide it anyway such that
// we get better error messages.
throw std::logic_error {};
}
template <typename T, typename = void>
struct can_directly : std::false_type {};
template <typename T>
struct can_directly
<
T,
decltype((void) (std::declval<std::ostream&>() << std::declval<const T&>()))
> : std::true_type {};
template <typename T, typename = void>
struct can_to_string : std::false_type {};
template <typename T>
struct can_to_string
<
T,
decltype((void) (std::declval<std::ostream&>() << to_string(std::declval<const T&>())))
> : std::true_type {};
template <typename T, typename = void>
struct can_member_str : std::false_type {};
template <typename T>
struct can_member_str
<
T,
decltype((void) (std::declval<std::ostream&>() << std::declval<const T&>().str()))
> : std::true_type {};
template <typename T>
constexpr out_methods
decide_how() noexcept
{
if (can_directly<T>::value)
return out_methods::directly;
else if (can_to_string<T>::value)
return out_methods::to_string;
else if (can_member_str<T>::value)
return out_methods::member_str;
else
return out_methods::not_at_all;
}
template <typename T>
void
out(std::ostream& os, const T& arg)
{
constexpr auto how = decide_how<T>();
static_assert(how != out_methods::not_at_all, "cannot format type");
out(os, arg, tag<how> {});
}
}
template <typename... Ts>
void
out(std::ostream& os, const Ts&... args)
{
const int dummy[] = {0, ((void) detail::out(os, args), 0)...};
(void) dummy;
}
फिर इसका उपयोग करें।
int
main()
{
std::ostringstream nl {"\n"}; // has `str` member
out(std::cout, streamy {}, nl, stringy {}, '\n');
}
समारोह decide_how
आप निर्णय लेने से कैसे उत्पादन एक दिया प्रकार है, भले ही वहाँ कई विकल्प उपलब्ध हैं में पूरी छूट देता है। विस्तार करना भी आसान है। उदाहरण के लिए, कुछ प्रकारों में str
एडीएल खोजने योग्य सक्षम to_string
नि: शुल्क फ़ंक्शन के बजाय सदस्य फ़ंक्शन होता है। (असल में, मैंने पहले ही ऐसा किया है।)
फ़ंक्शन detail::out
उपयुक्त आउटपुट विधि का चयन करने के लिए tag dispatching का उपयोग करता है।
can_HOW
भविष्यवाणियों को void_t
trick का उपयोग करके लागू किया गया है जो मुझे बहुत ही सुरुचिपूर्ण लगता है।
विविधता out
फ़ंक्शन “for each argument” trick का उपयोग करता है, जो मुझे और भी सुरुचिपूर्ण लगता है।
ध्यान दें कि कोड C++ 14 है और उसे एक अद्यतित कंपाइलर की आवश्यकता होगी।
क्या यह SFINAE है? तो जब 'to_string (x)' संकलित होता है, तो 'वापसी os << to_string (obj); 'अधिभार मौजूद है और अन्यथा नहीं? क्या मैं 'std :: conditional' के बजाय' std :: enable_if' का उपयोग कर सकता हूं? – Lingxi
मुझे लगता है कि '<< to_string (x)' अधिभार होने पर '<< x' संकलित नहीं होता है, अगर यह संभव है तो अच्छा होगा। – Lingxi
हां, यह SFINAE है। कृपया अद्यतन उत्तर देखें (विशेष रूप से आपकी दूसरी टिप्पणी के जवाब में)। मैंने 'std :: enable_if' का उपयोग करने के बारे में सोचा लेकिन मुझे सीधे-आगे समाधान नहीं मिला, इसलिए मैं स्वीकार्य रूप से कुछ हद तक भ्रमित 'std :: सशर्त' के साथ गया। – 5gon12eder
प्रयास करें
template <typename T>
void print_out(T t) {
print_out_impl(std::cout, t, 0);
}
template <typename OS, typename T>
void print_out_impl(OS& o, T t,
typename std::decay<decltype(
std::declval<OS&>() << std::declval<T>()
)>::type*) {
o << t;
}
template <typename OS, typename T>
void print_out_impl(OS& o, T t, ...) {
o << t.to_string();
}
@MSalters के जवाब के आधार पर (क्रेडिट उसे जाता है), यह मेरी समस्या हल करता है और एक पूर्ण उत्तर देना चाहिए।
#include <iostream>
#include <string>
#include <type_traits>
struct foo_t {};
std::string to_string(foo_t) {
return "foo_t";
}
template <class CharT, class Traits, class T>
typename std::enable_if<std::is_same<CharT, char>::value,
std::basic_ostream<CharT, Traits>&>::type
operator<<(std::basic_ostream<CharT, Traits>& os, const T& x) {
return os << to_string(x);
}
int main() {
std::cout << std::string{"123"} << std::endl;
std::cout << foo_t{} << std::endl;
}
- 1. समानता गड़बड़ सी # सूची <T> क्रमबद्ध करने में विफल क्यों विफल रहता है?
- 2. कथन "cout << '\\\\'; क्यों विफल नहीं है?
- 3. "ऑपरेटर <<" क्या कहा जाता है?
- 4. "<<<" ऑपरेटर का नाम क्या है?
- 5. document.createEvent विफल रहता है
- 6. WebBrowserTask विफल रहता है
- 7. <% $, <% @, <% =, <% # ... सौदा क्या है?
- 8. ओवरलोडिंग ऑपरेटर << - सी ++
- 9. ऑपरेटर बनाना << आभासी?
- 10. << ऑपरेटर और प्रत्यावर्तन
- 11. ऑपरेटर << ओवरलोडिंग ओस्ट्रीम
- 12. कॉलिंग ऑपरेटर << gdb
- 13. जावा बिटवाइज़ ऑपरेटर <<
- 14. जावास्क्रिप्ट बुकमार्कलेट कुछ साइटों पर विफल रहता है, भूतिया नया बनाता है <html> पेज
- 15. स्टेटिक बनाम सदस्य ऑपरेटर अधिभार: std :: ऑपरेटर << और std :: ostream :: ऑपरेटर <<
- 16. 'ऑपरेटर <<' के लिए 'std :: cout <<' में अस्पष्ट अधिभार <<
- 17. BOOST_CHECK कस्टम प्रकार के लिए ऑपरेटर <<
- 18. खाका समारोह प्रकार कटौती और ऑपरेटर << C++
- 19. PHP क्या <<< मतलब है?
- 20. sendMessage दोनों दिशाओं में विफल रहता है Apple View <-> सिम्युलेटर में आईफोन
- 21. पॉपन "sh: <command>" के साथ विफल रहता है: नहीं मिला "
- 22. ऑटॉमेबल <object> प्रोजेक्ट करते समय Automapper विफल रहता है जब ऑब्जेक्ट में संग्रह संपत्ति
- 23. XML पार्स स्ट्रिंग विफल रहता है स्ट्रिंग <?xml... ?> अनुभाग
- 24. Caffe:</p> <pre><code>python draw_net.py test.protxt test.png </code></pre> <p>यह आकर्षित करने के लिए विफल रहता है: ड्राइंग सीएनएन नेट
- 25. DQL क्वेरी विफल रहता है
- 26. डाउनलोड dSYM विफल रहता है
- 27. गतिशील_कास्ट कैसे विफल रहता है?
- 28. gclient runhooks विफल रहता है
- 29. पुशिंग विफल रहता है - गिटक्रैकन
- 30. जब रीडी विफल रहता है
मैं मानता हूं कि यह मामला उस मामले के लिए आसान है जहां आप केवल 'ऑपरेटर <<' को ''' 'टाइप' टाइप 'टाइप करने के लिए अपने' नेमस्पेस 'या अन्यथा' to_string (टी) 'और कुछ भी नहीं चाहते हैं, जो कि, माना जाता है कि ओपी के पास क्या है के लिए पूछा, तो +1। यदि आपको आगे प्रेषण करने की आवश्यकता है, तो यह काम नहीं करेगा। साथ ही, इस समाधान द्वारा उत्पन्न त्रुटि संदेश उतना सहायक नहीं हो सकते जितना वे हो सकते हैं। – 5gon12eder
यह अच्छा है। लेकिन फिर मुझे प्रत्येक प्रकार के लिए 'ऑपरेटर <<() 'अधिभार करना होगा जो केवल' to_string()' overloaded है। मैं इस तरह के कठिन काम से बचना चाहता हूँ। – Lingxi
@ling क्या? आपको ऐसा क्यों लगता है कि आपको ऐसा करना है? – Yakk