Consider the following code:
#include <string>
#include <iostream>
#include <memory>
#include <utility>
#include <vector>
#include <array>
#include <tuple>
#include <variant>
#include <algorithm>
#include <numeric>
#include <type_traits>
#include <functional>
#include <stdexcept>
// a few global things that will be needed by Heap and friends
// credit https://stackoverflow.com/questions/34099597/check-if-a-type-is-passed-in-variadic-template-parameter-pack
template<typename T, typename... Ts>
constexpr bool contained_in = std::disjunction_v<std::is_same<T, Ts>...>;
// credit https://stackoverflow.com/questions/18986560/check-variadic-templates-parameters-for-uniqueness
template <typename T>
struct Base {};
template <typename... Ts>
struct Types : Base<Ts>...
{
template <typename T>
constexpr auto operator+(Base<T>)
{
if constexpr (std::is_base_of_v<Base<T>, Types>)
return Types{};
else
return Types<Ts..., T>{};
}
constexpr size_t size() const
{
return sizeof...(Ts);
}
};
template <typename... Ts>
constexpr bool unique_types = ( (Types<>{} + ... + Base<Ts>{}).size() == sizeof...(Ts) );
// credit https://stackoverflow.com/questions/42580997/check-if-one-set-of-types-is-a-subset-of-the-other/
template <typename T, typename U>
constexpr bool is_subset_of = false;
template <template <typename, typename...> typename T, typename ...Ts, template <typename, typename...> typename U, typename ...Us>
constexpr bool is_subset_of<T<Ts...>, U<Us...>>
= (contained_in<Ts, Us...> and ...);
template <typename T, typename U>
constexpr bool mutual_overlap = false;
template <template <typename, typename...> typename T, typename ...Ts, template <typename, typename...> typename U, typename ...Us>
constexpr bool mutual_overlap<T<Ts...>, U<Us...>>
= (is_subset_of<T<Ts...>, U<Us...>> or is_subset_of<U<Us...>, T<Ts...>>);
template <typename ...Ts>
class Collection {
};
int main() {
// check for the helper functions
std::cout << "iso ci cif " << is_subset_of<Collection<float>, Collection<int, float>> << std::endl;
std::cout << "iso cif ci " << is_subset_of<Collection<int, float>, Collection<int>> << std::endl;
std::cout << "iso cif cif " << is_subset_of<Collection<int, float>, Collection<int, float>> << std::endl;
std::cout << "iso cif cfi " << is_subset_of<Collection<int, float>, Collection<float, int>> << std::endl;
std::cout << "iso cic cif " << is_subset_of<Collection<int, char>, Collection<int, float>> << std::endl;
std::cout << "iso ccf cud " << is_subset_of<Collection<char, float>, Collection<uint, double>> << std::endl;
std::cout << "iso ccf ccfid " << is_subset_of<Collection<char, float>, Collection<char, float, int, double>> << std::endl;
std::cout << "iso ccfu ccfid " << is_subset_of<Collection<char, float, uint>, Collection<char, float, int, double>> << std::endl;
std::cout << "mo ci cif " << mutual_overlap<Collection<float>, Collection<int, float>> << std::endl;
std::cout << "mo cif ci " << mutual_overlap<Collection<int, float>, Collection<int>> << std::endl;
std::cout << "mo cif cif " << mutual_overlap<Collection<int, float>, Collection<int, float>> << std::endl;
std::cout << "mo cif cfi " << mutual_overlap<Collection<int, float>, Collection<float, int>> << std::endl;
std::cout << "mo cic cif " << mutual_overlap<Collection<int, char>, Collection<int, float>> << std::endl;
std::cout << "mo ccf cud " << mutual_overlap<Collection<char, float>, Collection<uint, double>> << std::endl;
std::cout << "mo ccf ccfid " << mutual_overlap<Collection<char, float>, Collection<char, float, int, double>> << std::endl;
std::cout << "mo ccfu ccfid " << mutual_overlap<Collection<char, float, uint>, Collection<char, float, int, double>> << std::endl;
return 0;
}
(the headers are not all strictly necessary and is copypasted off a project)
Testing the results with GCC and clang, they give different results. I'm thinking GCC is correct here, from the fact that the results are as intended, but why does clang mark all of these false?
Both are compiled with the trunk version.