I have a problem while defining a template class containing T.
namespace { template <typename T1, typename T2 = T1, typename Test = bool> struct is_comparable : std::integral_constant<bool, false> {}; template <typename T1, typename T2> struct is_comparable<T1, T2, decltype(std::declval<const std::decay_t<T1>>() == std::declval<const std::decay_t<T2>>())> : std::integral_constant<bool, true> {}; } template <class T> class Wrapper { public: Wrapper() = default; void set(const T& val) { if constexpr (is_comparable<T>::value) { if (_val == val) return; } _val = val; onChanged(); } void onChanged() { ... } private: T _val; }; The problem arises for std::map with a non-comparable value_type.
void foo() { Wrapper<std::map<int, std::any>> mapWrapper; mapWrapper.set(std::map<int, std::any>()); // error occurs. } here's the cause.
static_assert(is_comparable<int>::value == true); // ok static_assert(is_comparable<std::any>::value == false); // ok static_assert(is_comparable<std::map<int, std::any>>::value == false); // error. I'm expecting false, but it's true. // some code blocks in void Wrapper<T>::set(const T& val) if constexpr (is_comparable<T>::value) { // enter here when T == std::map<int, std::any> // and compile time error occurs. if (_val == val) return; } so I defined like this for avoiding the error, but is_comparable<T1, T2> is still used instead.
template <typename K1, typename V1, typename K2, typename V2> struct is_comparable<std::map<K1, V1>, std::map<K2, V2>, std::enable_if_t<is_comparable<K1, K2>::value && is_comparable<V1, V2>::value, bool>> : std::integral_constant<bool, true> {}; is there any good resolution?
edit: full source codes and error messages is here.
#include <type_traits> #include <map> #include <any> namespace { template <typename T1, typename T2 = T1, typename Test = bool> struct is_comparable : std::integral_constant<bool, false> {}; template <typename T1, typename T2> struct is_comparable<T1, T2, decltype(std::declval<const std::decay_t<T1>>() == std::declval<const std::decay_t<T2>>())> : std::integral_constant<bool, true> {}; template <typename K1, typename V1, typename K2, typename V2> struct is_comparable<std::map<K1, V1>, std::map<K2, V2>, std::enable_if_t<is_comparable<K1, K2>::value&& is_comparable<V1, V2>::value, bool>> : std::integral_constant<bool, true> {}; } // unnamed namespace template <class T> class Wrapper { public: Wrapper() = default; void set(const T& val) { if constexpr (is_comparable<T>::value) { if (_val == val) return; } _val = val; onChanged(); } void onChanged() { /* any expensive operations. */ } private: T _val; }; static_assert(is_comparable<int>::value == true); static_assert(is_comparable<std::any>::value == false); // static_assert(is_comparable<std::map<int, std::any>>::value == false); // error void foo() { Wrapper<std::map<int, std::any>> mapWrapper; mapWrapper.set(std::map<int, std::any>()); // error occurs. } int main(int /*argc*/, char** /*argv*/) { foo(); return 0; } messages
Build started... 1>------ Build started: Project: TemplateTest, Configuration: Debug x64 ------ 1>main.cpp 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\utility(368,56): error C2676: binary '==': 'const _Ty2' does not define this operator or a conversion to a type acceptable to the predefined operator 1>
with 1> [ 1> _Ty2=std::any 1> ] 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\utility(367,27): message : could be 'bool std::operator ==(const std::pair<_Ty1,_Ty2> &,const std::pair<_Ty1,_Ty2> &)' 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\utility(368,48): message : 'bool std::operator ==(const std::pair<_Ty1,_Ty2> &,const std::pair<_Ty1,_Ty2> &)': could not deduce template argument for 'const std::pair<_Ty1,_Ty2> &' from 'const _Ty2' 1> with 1>
[ 1> _Ty2=std::any 1> ] 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\utility(367,27): message : or 'bool std::operator ==(const std::pair<_Ty1,_Ty2> &,const std::pair<_Ty1,_Ty2> &)' 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\utility(368,48): message : 'bool std::operator ==(const std::pair<_Ty1,_Ty2> &,const std::pair<_Ty1,_Ty2> &)': could not deduce template argument for 'const std::pair<_Ty1,_Ty2> &' from 'const _Ty2' 1> with 1>
[ 1> _Ty2=std::any 1> ] 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\tuple(672,27): message : or 'bool std::operator ==(const std::tuple<_Types...> &,const std::tuple<_Types...> &)' 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\utility(368,48): message : 'bool std::operator ==(const std::tuple<_Types...> &,const std::tuple<_Types...> &)': could not deduce template argument for 'const std::tuple<_Types...> &' from 'const _Ty2' 1> with 1>
[ 1> _Ty2=std::any 1> ] 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\xutility(1441,5): message : or 'bool std::operator ==(const std::reverse_iterator<_BidIt> &,const std::reverse_iterator<_BidIt2> &) noexcept()' 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\utility(368,48): message : 'bool std::operator ==(const std::reverse_iterator<_BidIt> &,const std::reverse_iterator<_BidIt2> &) noexcept()': could not deduce template argument for 'const std::reverse_iterator<_BidIt> &' from 'const _Ty2' 1> with 1> [ 1>
_Ty2=std::any 1> ] 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\xutility(3969,5): message : or 'bool std::operator ==(const std::move_iterator<_Iter> &,const std::move_iterator<_Iter2> &) noexcept()' 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\utility(368,48): message : 'bool std::operator ==(const std::move_iterator<_Iter> &,const std::move_iterator<_Iter2> &) noexcept()': could not deduce template argument for 'const std::move_iterator<_Iter> &' from 'const _Ty2' 1> with 1> [ 1> _Ty2=std::any 1> ] 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\xmemory(894,30): message : or 'bool std::operator ==(const std::allocator<_Ty> &,const std::allocator<_Other> &) noexcept' 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\utility(368,48): message : 'bool std::operator ==(const std::allocator<_Ty> &,const std::allocator<_Other> &) noexcept': could not deduce template argument for 'const std::allocator<_Ty> &' from 'const _Ty2' 1>
with 1> [ 1> _Ty2=std::any 1> ] 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\map(399,17): message : or 'bool std::operator ==(const std::map<_Kty,_Ty,_Pr,_Alloc> &,const std::map<_Kty,_Ty,_Pr,_Alloc> &)' 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\utility(368,48): message : 'bool std::operator ==(const std::map<_Kty,_Ty,_Pr,_Alloc> &,const std::map<_Kty,_Ty,_Pr,_Alloc> &)': could not deduce template argument for 'const std::map<_Kty,_Ty,_Pr,_Alloc> &' from 'const _Ty2' 1> with 1> [ 1> _Ty2=std::any 1> ] 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\map(630,17): message : or 'bool std::operator ==(const std::multimap<_Kty,_Ty,_Pr,_Alloc> &,const std::multimap<_Kty,_Ty,_Pr,_Alloc> &)' 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\utility(368,48): message : 'bool std::operator ==(const std::multimap<_Kty,_Ty,_Pr,_Alloc> &,const std::multimap<_Kty,_Ty,_Pr,_Alloc> &)': could not deduce template argument for 'const std::multimap<_Kty,_Ty,_Pr,_Alloc> &' from 'const _Ty2' 1> with 1> [ 1> _Ty2=std::any 1> ] 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\xstddef(212): message : see reference to function template instantiation 'bool std::operator ==<const int,std::any>(const std::pair<const int,std::any> &,const std::pair<const int,std::any> &)' being compiled 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\xutility(4964): message : see reference to function template instantiation 'bool std::equal_to::operator ()<const std::pair<const int,std::any>&,const std::pair<const int,std::any>&>(_Ty1,_Ty2) noexcept(false) const' being compiled 1> with 1> [ 1>
_Ty1=const std::pair<const int,std::any> &, 1> _Ty2=const std::pair<const int,std::any> & 1> ] 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\xutility(4995): message : see reference to function template instantiation 'bool std::equal<_InIt1,_InIt2,std::equal_to>(const _InIt1,const _InIt1,const _InIt2,_Pr)' being compiled 1> with 1> [ 1> _InIt1=std::_Tree_unchecked_const_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const int,std::any>>>,std::_Iterator_base0>, 1>
_InIt2=std::_Tree_unchecked_const_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const int,std::any>>>,std::_Iterator_base0>, 1>
_Pr=std::equal_to 1> ] 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\map(399): message : see reference to function template instantiation 'bool std::equal<std::_Tree_unchecked_const_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const int,std::any>>>,std::_Iterator_base0>,std::_Tree_unchecked_const_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const int,std::any>>>,std::_Iterator_base0>>(const _InIt1,const _InIt1,const _InIt2)' being compiled 1> with 1> [ 1> _InIt1=std::_Tree_unchecked_const_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const int,std::any>>>,std::_Iterator_base0>, 1>
_InIt2=std::_Tree_unchecked_const_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const int,std::any>>>,std::_Iterator_base0> 1> ] 1>C:\Project\TemplateTest\TemplateTest\main.cpp(26,1): message : see reference to function template instantiation 'bool std::operator ==<int,std::any,std::less,std::allocator<std::pair<const int,std::any>>>(const std::map<int,std::any,std::less,std::allocator<std::pair<const int,std::any>>> &,const std::map<int,std::any,std::less,std::allocator<std::pair<const int,std::any>>> &)' being compiled 1>C:\Project\TemplateTest\TemplateTest\main.cpp(23,1): message : while compiling class template member function 'void Wrapperstd::map<int,std::any,std::less<int,std::allocator<std::pair<const int,std::any>>>>::set(const T &)' 1> with 1> [ 1>
T=std::map<int,std::any,std::less,std::allocator<std::pair<const int,std::any>>> 1> ] 1>C:\Project\TemplateTest\TemplateTest\main.cpp(44,19): message : see reference to function template instantiation 'void Wrapperstd::map<int,std::any,std::less<int,std::allocator<std::pair<const int,std::any>>>>::set(const T &)' being compiled 1> with 1>
[ 1>
T=std::map<int,std::any,std::less,std::allocator<std::pair<const int,std::any>>> 1> ] 1>C:\Project\TemplateTest\TemplateTest\main.cpp(43,38): message : see reference to class template instantiation 'Wrapperstd::map<int,std::any,std::less<int,std::allocator<std::pair<const int,std::any>>>>' being compiled 1>Done building project "TemplateTest.vcxproj" -- FAILED. ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ========== ========== Build started at 5:43 PM and took 00.914 seconds ==========
(tried in msvc++ 14.35 / C++17)
decltype(std::declval<std::map<int, std::any>>() == std::declval<std::map<int, std::any>>())isbool. It's not clear what type you expected it to be.