समारोह जोर देते हैं
सी में मैक्रो है assert
और जब यह काम करता है तो मैं मुख्य रूप से इसे पसंद नहीं करता क्योंकि इसमें स्ट्रिंग को प्रिंट करने का कोई अच्छा तरीका नहीं है। परिणामस्वरूप मैंने assert
c ++ के लिए एक बेहतर संस्करण बनाने का प्रयास किया । हालाँकि, मैंने इसे इंजीनियर के रूप में छोड़ दिया और कुछ ऐसा किया, जो कई बार धीमा हो जाता है, और कुछ ऐसा जिसका मैं उपयोग नहीं करता। मैं इसे कैसे सुधार सकता हूँ?
assert.hh
#ifndef ASSERT_HH
#define ASSERT_HH
#include <iostream>
#include <utility>
#include <tuple>
namespace turtle
{
/* these macros are needed because #__VA_ARGS__ will include the comma in the string
* for example: macro(...) __VA_ARGS__
* macro(a,b) -> expands to "a,b"
* instead of "a","b"
*/
#define TURTLE_FIRST_(a, ...) a
#define TURTLE_SECOND_(a, b, ...) b
#define TURTLE_FIRST(...) TURTLE_FIRST_(__VA_ARGS__,)
#define TURTLE_SECOND(...) TURTLE_SECOND_(__VA_ARGS__,)
#define TURTLE_EMPTY()
#define TURTLE_EVAL(...) TURTLE_EVAL1024(__VA_ARGS__)
#define TURTLE_EVAL1024(...) TURTLE_EVAL512(TURTLE_EVAL512(__VA_ARGS__))
#define TURTLE_EVAL512(...) TURTLE_EVAL256(TURTLE_EVAL256(__VA_ARGS__))
#define TURTLE_EVAL256(...) TURTLE_EVAL128(TURTLE_EVAL128(__VA_ARGS__))
#define TURTLE_EVAL128(...) TURTLE_EVAL64(TURTLE_EVAL64(__VA_ARGS__))
#define TURTLE_EVAL64(...) TURTLE_EVAL32(TURTLE_EVAL32(__VA_ARGS__))
#define TURTLE_EVAL32(...) TURTLE_EVAL16(TURTLE_EVAL16(__VA_ARGS__))
#define TURTLE_EVAL16(...) TURTLE_EVAL8(TURTLE_EVAL8(__VA_ARGS__))
#define TURTLE_EVAL8(...) TURTLE_EVAL4(TURTLE_EVAL4(__VA_ARGS__))
#define TURTLE_EVAL4(...) TURTLE_EVAL2(TURTLE_EVAL2(__VA_ARGS__))
#define TURTLE_EVAL2(...) TURTLE_EVAL1(TURTLE_EVAL1(__VA_ARGS__))
#define TURTLE_EVAL1(...) __VA_ARGS__
#define TURTLE_DEFER1(m) m TURTLE_EMPTY()
#define TURTLE_DEFER2(m) m TURTLE_EMPTY TURTLE_EMPTY()()
#define TURTLE_IS_PROBE(...) TURTLE_SECOND(__VA_ARGS__, 0)
#define TURTLE_PROBE() ~, 1
#define TURTLE_CAT(a, b) a ## b
#define TURTLE_NOT(x) TURTLE_IS_PROBE(TURTLE_CAT(TURTLE__NOT_, x))
#define TURTLE__NOT_0 TURTLE_PROBE()
#define TURTLE_BOOL(x) TURTLE_NOT(TURTLE_NOT(x))
#define TURTLE_IF_ELSE(condition) TURTLE__IF_ELSE(TURTLE_BOOL(condition))
#define TURTLE__IF_ELSE(condition) TURTLE_CAT(TURTLE__IF_, condition)
#define TURTLE__IF_1(...) __VA_ARGS__ TURTLE__IF_1_ELSE
#define TURTLE__IF_0(...) TURTLE__IF_0_ELSE
#define TURTLE__IF_1_ELSE(...)
#define TURTLE__IF_0_ELSE(...) __VA_ARGS__
#define TURTLE_COMMA ,
#define TURTLE_HAS_ARGS(...) TURTLE_BOOL(TURTLE_FIRST(TURTLE__END_OF_ARGUMENTS_ __VA_ARGS__)())
#define TURTLE__END_OF_ARGUMENTS_() 0
#define TURTLE_MAP(m, first, ...) \
m(first) \
TURTLE_IF_ELSE(TURTLE_HAS_ARGS(__VA_ARGS__))( \
TURTLE_COMMA TURTLE_DEFER2(TURTLE__MAP)()(m, __VA_ARGS__) \
)( \
/* Do nothing, just terminate */ \
)
#define TURTLE__MAP() TURTLE_MAP
#define TURTLE__STRINGIZE(x) TURTLE___STRINGIZE(x)
#define TURTLE___STRINGIZE(x) #x
#define TURTLE_STRINGIZE(x) __FILE__ " line " TURTLE__STRINGIZE(__LINE__) ": assertion {" #x
template<typename... Args, typename Text>
constexpr auto assert_basic(const std::tuple<Args...> &arg, const Text &text)
{
if constexpr (sizeof...(Args) == 1) {
if (!std::get<0>(arg)) {
std::cerr << text << "} failed\n";
return true;
}
} else {
if (!std::get<0>(arg)) {
std::cerr << text << "} failed -> "
<< std::get<1>(arg) << '\n';
return true;
}
}
return false;
}
template<std::size_t Index, typename Result, typename... Args>
constexpr auto assert_tuple_args_helper(const Result &result, const std::tuple<Args...> &tuple_args_basic)
{
if constexpr (Index >= sizeof...(Args)) {
return result;
} else if constexpr (Index + 1 >= sizeof...(Args) &&
std::is_convertible_v<std::tuple_element_t<Index, std::decay_t<decltype(tuple_args_basic)>>, int>) {
return assert_tuple_args_helper<Index + 1>(std::tuple_cat(result,
std::tuple<decltype(std::tuple{
std::get<Index>(tuple_args_basic)})>{
std::tuple{std::get<Index>(
tuple_args_basic)}}),
tuple_args_basic);
} else if constexpr (
std::is_convertible_v<std::tuple_element_t<Index, std::decay_t<decltype(tuple_args_basic)>>, int>
&&
std::is_convertible_v<std::tuple_element_t<Index + 1, std::decay_t<decltype(tuple_args_basic)>>, int>) {
return assert_tuple_args_helper<Index + 1>(
std::tuple_cat(result, std::tuple<decltype(std::tuple{std::get<Index>(tuple_args_basic)})>{
std::tuple{std::get<Index>(tuple_args_basic)}}), tuple_args_basic);
} else if constexpr (
std::is_convertible_v<std::tuple_element_t<Index, std::decay_t<decltype(tuple_args_basic)>>, int>
&& !std::is_convertible_v<std::tuple_element_t<
Index + 1, std::decay_t<decltype(tuple_args_basic)>>, int>) {
return assert_tuple_args_helper<Index + 2>(
std::tuple_cat(result, std::tuple<decltype(std::tuple{std::get<Index>(tuple_args_basic),
std::get<Index + 1>(
tuple_args_basic)})>
{std::tuple{std::get<Index>(tuple_args_basic),
std::get<Index + 1>(
tuple_args_basic)}}), tuple_args_basic);
}
}
template<std::size_t TupleIndex, typename Result, typename... Args>
constexpr auto assert_tuple_text_indices_helper(const Result& result, std::size_t old_index, const std::tuple<Args...>& tuple)
{
if constexpr (TupleIndex < std::tuple_size_v<std::decay_t<decltype(tuple)>>) {
std::size_t next_index = old_index + std::tuple_size_v<std::decay_t<decltype(std::get<TupleIndex>(tuple))>>;
return assert_tuple_text_indices_helper<TupleIndex+1>(std::tuple_cat(result, std::tuple{old_index}), next_index, tuple);
} else {
return result;
}
}
template<typename Text, typename... Args>
constexpr auto assert(const Text& text, Args &&... args)
{
const auto &tuple_args = assert_tuple_args_helper<0>(std::tuple{}, std::tuple{args...});
constexpr auto tuple_text_indices = assert_tuple_text_indices_helper<0>(std::tuple{}, 0, decltype(tuple_args){});
[&]<std::size_t... Indices>(std::index_sequence<Indices...>) {
if ((assert_basic(std::get<Indices>(tuple_args), text[std::get<Indices>(tuple_text_indices)]) | ...)) {
std::exit(1);
}
}(std::make_index_sequence<std::tuple_size_v<std::decay_t<decltype(tuple_args)>>>{});
}
}
#define assert(...) turtle::assert(std::array{TURTLE_EVAL(TURTLE_MAP(TURTLE_STRINGIZE, __VA_ARGS__))}, __VA_ARGS__)
#endif /* ASSERT_HH */
main.cc
#include "assert.hh"
/* testing */
int main()
{
int a, b, c, d;
std::cin >> a >> b >> c >> d;
assert(__LINE__ % 2 == 1, a < b, "a must be less than b", b < c, "b must be less than c", c < d, "c must be less than d");
assert(__LINE__ % 2 == 1, __FILE__[2] < 80);
}
जवाब
जब आप प्रदर्शन की अड़चनों की तलाश कर रहे हैं, तो यह नामित भागों पर ध्यान केंद्रित करने में मदद कर सकता है TURTLE
। ;) लेकिन मुझे नहीं लगता कि यह आपकी मुख्य समस्या है।
ऐसा लगता है कि आप जो करना चाहते हैं, वह केवल एक संदेश है जो सही है?
#define myAssert(x, msg) assert((x) && msg)
यह तब तक काम करता है, जब तक कि आप हमेशा ऐसे परकोटे को दोगुना करने के लिए संजीदा होते हैं, जिन्हें डबल परेंस की जरूरत होती है:
myAssert(x < 2, "x is too large");
myAssert((foo<int,int> < 2), "foo<int,int> is too large");
यदि आप परनों को खत्म करना चाहते हैं, तो मैं उस समस्या को कम कर दूंगा "मैं एक पैकेट से अंतिम मैक्रो तर्क कैसे निकालूं?" एक समझदार उत्तर देने वाले का सुझाव है कि आप उस प्रश्न को अनसुना कर दें और संदेश को पहले तर्क के रूप में डालें:
#define myAssert(msg, ...) assert((__VA_ARGS__) && msg)
myAssert("x is too large", x < 2);
myAssert("foo<int,int> is too large", foo<int,int> < 2);