有没有办法检查 class 是否可转换为某些模板实例化?
Is there a way to check if a class is convertible to some template instantiation?
问题
这里是一些代码
struct Base
{
int SomeMethod(const Base&);
template <class T> int SomeMethod(const T&);
};
template <class Tag> struct Derived : Base
{
using Base::SomeMethod;
int SomeMethod(const Derived&);
template <class OtherTag> std::enable_if_t<!std::is_same_v<Tag, OtherTag>> SomeMethod(Derived<OtherTag>) = delete;
};
struct tag {};
struct another_tag {};
struct ImplicitOpToAnotherTagInstantiation { operator Derived<another_tag>() const; };
有没有什么东西(Derived::SomeMethod
重载)我可以在 Derived
中写入而不触及 Base
,这会导致下一个代码中的编译器错误?
Derived<tag>{}.SomeMethod(ImplicitOpToAnotherTagInstantiation {});
下一个代码应该是正确的
struct ImplicitOpToBase { operator Base() const; };
Derived<tag>{}.SomeMethod(Derived<tag>{});
Derived<tag>{}.SomeMethod(Base{});
Derived<tag>{}.SomeMethod(ImplicitOpToBase{});
// Derived<tag>{}.SomeMethod(Derived<another_tag>{}); compiler error!
我尝试了什么
- 首先想到的是做这样的事情:
template <class Tag> struct Derived : Base
{
using Base::SomeMethod;
int SomeMethod(const Derived&);
template <class OtherTag> std::enable_if_t<!std::is_same_v<Tag, OtherTag>> SomeMethod(Derived<OtherTag>) = delete;
template <class T, class OtherTag> std::enable_if_t<!std::is_same<Tag, OtherTag> && std::is_convertible<Tag, Derived<OtherTag>>> SomeMethod(T) = delete;
};
但它不起作用,因为如果没有像这样的显式实例化
,编译器无法推断 OtherTag
Derived<tag>{}.SomeMethod<ImplicitOpToAnotherTagInstantiation, another_tag>(); // error: deleted function!
- 再三考虑:
template <class Tag> struct Derived : Base
{
using Base::SomeMethod;
int SomeMethod(const Derived&);
template <class OtherTag> std::enable_if_t<!std::is_same_v<Tag, OtherTag>> SomeMethod(Derived<OtherTag>) = delete;
template <class T> std::enable_if_t<!std::is_same<T, Derived> && std::is_convertible<T, Base>> SomeMethod(T) = delete;
};
但下一个代码会导致编译器错误,而此时不应该:
Derived<tag>{}.SomeMethod(ImplicitOpToBase{});
主要用途
我正在尝试为 std::string
创建某种强类型定义,其中 Base
是 std::string
,Derived
是我的 TaggedString
,SomeMethod
是 std::string::assign
。我想用另一个标签的类型禁用 assign
方法,我在问题中解释了一些困难。为了 reader,我忽略了一个事实,即 TaggedString
可以隐式转换为 std::string_view
。
template <class Tag> struct TaggedString : std::string
{
using std::string::assign;
TaggedString& assign(const TaggedString& other) { std::string::assign(other); return *this; }
template <class OtherTag> std::enable_if_t<!std::is_same_v<Tag, OtherTag>> assign(TaggedString<OtherTag>) = delete;
};
Here 是可以玩的。
没有。有无限组可能的转换,甚至是无限组到 Derived<SomeUnknownType>
的转换。您的编译器无法测试所有可能的类型 T 以查看 ImplicitOpToAnotherTagInstantiation
是否可以转换为 Derived<T>
.
它可以测试一个有限集,如果你提供的话。但是你只有 tag
,一个 exclude 的类型。无限类型集减去一种类型仍然是无限类型集。
问题
这里是一些代码
struct Base
{
int SomeMethod(const Base&);
template <class T> int SomeMethod(const T&);
};
template <class Tag> struct Derived : Base
{
using Base::SomeMethod;
int SomeMethod(const Derived&);
template <class OtherTag> std::enable_if_t<!std::is_same_v<Tag, OtherTag>> SomeMethod(Derived<OtherTag>) = delete;
};
struct tag {};
struct another_tag {};
struct ImplicitOpToAnotherTagInstantiation { operator Derived<another_tag>() const; };
有没有什么东西(Derived::SomeMethod
重载)我可以在 Derived
中写入而不触及 Base
,这会导致下一个代码中的编译器错误?
Derived<tag>{}.SomeMethod(ImplicitOpToAnotherTagInstantiation {});
下一个代码应该是正确的
struct ImplicitOpToBase { operator Base() const; };
Derived<tag>{}.SomeMethod(Derived<tag>{});
Derived<tag>{}.SomeMethod(Base{});
Derived<tag>{}.SomeMethod(ImplicitOpToBase{});
// Derived<tag>{}.SomeMethod(Derived<another_tag>{}); compiler error!
我尝试了什么
- 首先想到的是做这样的事情:
template <class Tag> struct Derived : Base
{
using Base::SomeMethod;
int SomeMethod(const Derived&);
template <class OtherTag> std::enable_if_t<!std::is_same_v<Tag, OtherTag>> SomeMethod(Derived<OtherTag>) = delete;
template <class T, class OtherTag> std::enable_if_t<!std::is_same<Tag, OtherTag> && std::is_convertible<Tag, Derived<OtherTag>>> SomeMethod(T) = delete;
};
但它不起作用,因为如果没有像这样的显式实例化
,编译器无法推断OtherTag
Derived<tag>{}.SomeMethod<ImplicitOpToAnotherTagInstantiation, another_tag>(); // error: deleted function!
- 再三考虑:
template <class Tag> struct Derived : Base
{
using Base::SomeMethod;
int SomeMethod(const Derived&);
template <class OtherTag> std::enable_if_t<!std::is_same_v<Tag, OtherTag>> SomeMethod(Derived<OtherTag>) = delete;
template <class T> std::enable_if_t<!std::is_same<T, Derived> && std::is_convertible<T, Base>> SomeMethod(T) = delete;
};
但下一个代码会导致编译器错误,而此时不应该:
Derived<tag>{}.SomeMethod(ImplicitOpToBase{});
主要用途
我正在尝试为 std::string
创建某种强类型定义,其中 Base
是 std::string
,Derived
是我的 TaggedString
,SomeMethod
是 std::string::assign
。我想用另一个标签的类型禁用 assign
方法,我在问题中解释了一些困难。为了 reader,我忽略了一个事实,即 TaggedString
可以隐式转换为 std::string_view
。
template <class Tag> struct TaggedString : std::string
{
using std::string::assign;
TaggedString& assign(const TaggedString& other) { std::string::assign(other); return *this; }
template <class OtherTag> std::enable_if_t<!std::is_same_v<Tag, OtherTag>> assign(TaggedString<OtherTag>) = delete;
};
Here 是可以玩的。
没有。有无限组可能的转换,甚至是无限组到 Derived<SomeUnknownType>
的转换。您的编译器无法测试所有可能的类型 T 以查看 ImplicitOpToAnotherTagInstantiation
是否可以转换为 Derived<T>
.
它可以测试一个有限集,如果你提供的话。但是你只有 tag
,一个 exclude 的类型。无限类型集减去一种类型仍然是无限类型集。