Created
March 21, 2022 20:42
-
-
Save vladiant/465f949c50a2739765faa7748b04d9c8 to your computer and use it in GitHub Desktop.
Evolving a Nice Trick - Patrice Roy - CppCon 2021
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cmath> | |
class exact {}; | |
class floating {}; | |
template <class T> bool close_enough(T a, T b, exact) { | |
return a == b; | |
} | |
template <class T> bool close_enough(T a, T b, floating) { | |
return std::abs(a - b) <= static_cast<T>(0.000001); | |
} | |
struct false_type { enum { value = false }; }; | |
struct true_type { enum { value = true }; }; | |
template <class> struct is_floating : false_type { }; | |
template <> struct is_floating<float> : true_type { }; | |
template <> struct is_floating<double> : true_type { }; | |
template <> struct is_floating<long double> : true_type { }; | |
template <bool, class T, class F> struct static_if_else; | |
template <class T, class F> struct static_if_else<true, T, F> { | |
typedef T type; | |
}; | |
template <class T, class F> struct static_if_else<false, T, F> { | |
typedef F type; | |
}; | |
template <class T> | |
bool close_enough(T a, T b) { return close_enough(a, b, typename static_if_else<is_floating<T>::value, floating, exact>::type{}); } | |
int main() { | |
return close_enough(3,3) && | |
close_enough(3.0,3.000000001); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cmath> | |
#include <type_traits> | |
class exact {}; | |
class floating {}; | |
template <class T> bool close_enough(T a, T b, exact) { | |
return a == b; | |
} | |
template <class T> bool close_enough(T a, T b, floating) { | |
return std::abs(a - b) <= static_cast<T>(0.000001); | |
} | |
template <class T> | |
bool close_enough(T a, T b) { | |
return close_enough(a, b, typename std::conditional<std::is_floating_point<T>::value, floating, exact>::type{}); | |
} | |
int main() { | |
return close_enough(3,3) && | |
close_enough(3.0,3.000000001); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <type_traits> | |
class exact {}; | |
class floating {}; | |
template <class T> constexpr bool close_enough(T a, T b, exact) { return a == b; } | |
template <class T> constexpr T absolute(T val) { return val < 0? -val : val; } | |
template <class T> constexpr bool close_enough(T a, T b, floating) { | |
return absolute(a - b) <= static_cast<T>(0.000001); | |
} | |
template <class T> | |
constexpr bool close_enough(T a, T b) { | |
return close_enough(a, b, typename std::conditional< | |
std::is_floating_point<T>::value, floating, exact | |
>::type{}); | |
} | |
int main() { | |
static_assert(close_enough(3,3), ""); | |
static_assert(close_enough(3.0,3.000000001)); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <type_traits> | |
template <class T> | |
constexpr typename std::enable_if<!std::is_floating_point<T>::value, bool>::type | |
close_enough(T a, T b) { | |
return a == b; | |
} | |
template <class T> constexpr T absolute(T val) { return val < 0? -val : val; } | |
template <class T> | |
constexpr typename std::enable_if<std::is_floating_point<T>::value, bool>::type | |
close_enough(T a, T b) { | |
return absolute(a - b) <= static_cast<T>(0.000001); | |
} | |
int main() { | |
static_assert(close_enough(3,3), ""); | |
static_assert(close_enough(3.0,3.000000001)); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <type_traits> | |
template <class T> | |
constexpr std::enable_if_t<!std::is_floating_point<T>::value, bool> | |
close_enough(T a, T b) { return a == b; } | |
template <class T> constexpr T absolute(T val) { return val < 0? -val : val; } | |
template <class T> constexpr auto threshold = static_cast<T>(0.000001); | |
template <class T> | |
constexpr std::enable_if_t<std::is_floating_point<T>::value, bool> | |
close_enough(T a, T b) { | |
return absolute(a - b) <= threshold<T>; | |
} | |
int main() { | |
static_assert(close_enough(3,3), ""); | |
static_assert(close_enough(3.0,3.000000001)); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <type_traits> | |
template <class T> | |
constexpr std::enable_if_t<!std::is_floating_point_v<T>, bool> | |
close_enough(T a, T b) { return a == b; } | |
template <class T> constexpr T absolute(T val) { return val < 0? -val : val; } | |
template <class T> constexpr auto threshold = static_cast<T>(0.000001); | |
template <class T> | |
constexpr std::enable_if_t<std::is_floating_point_v<T>, bool> | |
close_enough(T a, T b) { | |
return absolute(a - b) <= threshold<T>; | |
} | |
int main() { | |
static_assert(close_enough(3,3), ""); | |
static_assert(close_enough(3.0,3.000000001)); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <type_traits> | |
template <class T> constexpr T absolute(T val) { return val < 0? -val : val; } | |
template <class T> constexpr auto threshold = static_cast<T>(0.000001); | |
template <class T> | |
constexpr bool close_enough(T a, T b) { | |
if constexpr(std::is_floating_point_v<T>) | |
return absolute(a - b) <= threshold<T>; | |
else | |
return a == b; | |
} | |
int main() { | |
static_assert(close_enough(3,3), ""); | |
static_assert(close_enough(3.0,3.000000001)); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <type_traits> | |
#include <concepts> | |
template <class T> constexpr T absolute(T val) { return val < 0? -val : val; } | |
template <class T> constexpr auto threshold = static_cast<T>(0.000001); | |
template <class T> requires std::integral<T> | |
constexpr bool close_enough(T a, T b) { | |
return a == b; | |
} | |
template <class T> requires std::floating_point<T> | |
constexpr bool close_enough(T a, T b) { | |
return absolute(a - b) <= threshold<T>; | |
} | |
int main() { | |
static_assert(close_enough(3,3), ""); | |
static_assert(close_enough(3.0,3.000000001)); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <type_traits> | |
#include <concepts> | |
template <class T> constexpr T absolute(T val) { return val < 0? -val : val; } | |
template <class T> constexpr auto threshold = static_cast<T>(0.000001); | |
template <std::integral T> | |
constexpr bool close_enough(T a, T b) { | |
return a == b; | |
} | |
template <std::floating_point T> | |
constexpr bool close_enough(T a, T b) { | |
return absolute(a - b) <= threshold<T>; | |
} | |
int main() { | |
static_assert(close_enough(3,3), ""); | |
static_assert(close_enough(3.0,3.000000001)); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <type_traits> | |
#include <concepts> | |
template <class T> constexpr T absolute(T val) { return val < 0? -val : val; } | |
template <class T> constexpr auto threshold = static_cast<T>(0.000001); | |
constexpr bool close_enough(std::integral auto a, std::integral auto b) { | |
return a == b; | |
} | |
constexpr bool close_enough(std::floating_point auto a, std::floating_point auto b) { | |
return absolute(a - b) <= threshold< | |
std::common_type_t<decltype(a), decltype(b)> | |
>; | |
} | |
int main() { | |
static_assert(close_enough(3,3), ""); | |
static_assert(close_enough(3.0,3.000000001)); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
https://www.youtube.com/watch?v=K8XnDhrJP7w |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment