Belirtilmemiş türler C ++ 20 'gerektirir' ifadelerinde nasıl kullanılabilir?
Bir türün argüman gerektiren belirli bir metoda sahip olması gerekliliğini ifade etmek için bir C ++ 20 kavramı yazmaya çalışıyorum, ancak bu kavramın amaçları için argüman türünün ne olduğu umrumda değil.
Şöyle bir şey yazmaya çalıştım:
template <typename T>
concept HasFooMethod = requires(T t, auto x)
{
{ t.Foo(x) } -> std::same_as<void>;
};
ancak, hem gcc hem de clang bunu reddeder ve bu şekilde bir gerekli ifadesinin parametre listesinde 'auto' kullanılamayacağı şeklinde bir hata verir.
Bir alternatif, 'x' türünü ikinci bir şablon parametresi olarak koymak olabilir:
template <typename T, typename TX>
concept HasFooMethod = requires(T t, TX x)
{
{ t.Foo(x) } -> std::same_as<void>;
};
ancak bu, TX'nin kavram her kullanıldığında açıkça belirtilmesini gerektirir, çıkarılamaz:
struct S { void Foo(int); };
static_assert(HasFooMethod<S>); // doesn't compile
static_assert(HasFooMethod<S, int>); // the 'int' must be specified
Foo'nun belirtilmemiş tipte bir argüman almasına izin veren bir kavram yazmanın herhangi bir yolu var mı ?
Kısıtlı bir şablon üye işlevi gerektiren soru Kavram tanımı çok benzerdir, ancak aynı değildir: bu soru, bir (şablonlu) yöntemin belirli bir kavramı karşılayan herhangi bir türü almasını nasıl gerektireceğini sorarken, bu soru bir yöntemin almasını gerektirmekle ilgilidir. bazı belirli türü bu türü belirtilmemiş ise, her ne kadar. Nicelik belirteçleri açısından, diğer soru (sınırlı) evrensel nicelemeyi sorarken, bu soru varoluşsal nicelemeyle ilgilidir. Diğer sorunun cevabı da benim durumum için geçerli değil.
Yanıtlar
Kavramlar, aradığınız işlevselliği sağlamayı amaçlamaz. Yani sağlamıyorlar.
Bir kavram, şablonları kısıtlamak, bir şablonun tanımında kullanmayı (veya en azından kullanmakta özgür olmak) niyetinde olduğu bir dizi ifade veya ifadeyi belirtmek içindir.
Çok kısıtladığınız şablon içinde, ifadeyi t.Foo(x)
yazarsanız, türünü bilirsiniz x
. Ya somut bir tür, bir şablon parametresi ya da bir şablon parametresinden türetilmiş bir addır. Her iki durumda da türü x
sınırlandırılan şablonda mevcuttur.
Eğer böyle bir şablon sınırlamak istiyorsanız Yani, türünü hem kullanabilir t
ve türünü x
. Her ikisi de o anda sizin için mevcuttur, bu nedenle böyle bir kısıtlama yaratmada sorun yoktur. Yani, kısıtlama, T
yalıtılmış bir tür olarak açık değildir ; T
ve arasındaki ilişkide X
.
Kavramların, kısıtlamanın gerçek kullanım yeriyle herhangi bir ilişkiden yoksun bir boşlukta çalışması amaçlanmamıştır. Kullanıcıların static_assert
sınıflarını onlara karşı yapabilmesi için tekli kavramlar oluşturmaya odaklanmamalısınız . Kavramlar, bir türün onları yerine getirip getirmediğini test etme amaçlı değildir (temelde sizin static_assert
yaptığınız şey budur); onları kullanan şablon tanımını kısıtlamak içindir .
Kısıtlamanızın olması gerekiyor FooCallableWith
, değil HasFooMethod
.
Buna yakın bir şey, dolaylı olarak (neredeyse) her şeye dönüşebilen bir adaptör türü tanımlanarak gerçekleştirilebilir:
struct anything
{
// having both these conversions allows Foo's argument to be either
// a value, an lvalue reference, or an rvalue reference
template <typename T>
operator T&();
template <typename T>
operator T&&();
};
Bu operatörlerin yalnızca değerlendirilmemiş bir bağlamda kullanılacağından (ve aslında tüm T türleri için uygulanamayacaklarından) uygulanmasına gerek olmadığını unutmayın.
O zaman HasFooMethod
şu şekilde yazılabilir:
template <typename T>
concept HasFooMethod = requires(T t, anything a)
{
{ t.Foo(a) } -> std::same_as<void>;
};