จะส่งต่อประกาศคลาสเทมเพลต C ++ ได้อย่างไร


105

กำหนดคลาสเทมเพลตดังต่อไปนี้:

template<typename Type, typename IDType=typename Type::IDType>
class Mappings
{
public:
    ...
    Type valueFor(const IDType& id) { // return value }
    ...
};

มีคนส่งต่อประกาศคลาสนี้ในไฟล์ส่วนหัวได้อย่างไร

คำตอบ:


108

นี่คือวิธีที่คุณจะทำ:

template<typename Type, typename IDType=typename Type::IDType>
class Mappings;

template<typename Type, typename IDType>
class Mappings
{
public:
    ...
    Type valueFor(const IDType& id) { // return value }
    ...
};

โปรดทราบว่าค่าเริ่มต้นอยู่ในการประกาศไปข้างหน้าและไม่อยู่ในคำจำกัดความที่แท้จริง


เป็นไปได้ที่จะประกาศคลาสที่มีค่าเริ่มต้นที่ระบุไว้ในคำจำกัดความ ดูคำตอบของฉัน
Elliott

ฉันไม่เห็นด้วย. มาตรฐาน says: "แม่แบบพารามิเตอร์จะไม่ได้รับการขัดแย้งเริ่มต้นสองประกาศที่แตกต่างกันอยู่ในขอบเขตเดียวกัน" และฉันไม่พบอะไรเกี่ยวกับค่าเริ่มต้นในการประกาศครั้งแรกเท่านั้น นอกจากนี้รหัสที่มีการประกาศไปข้างหน้าและค่าดีฟอลต์ในนิยามจะคอมไพล์และรันได้สำเร็จ คุณแน่ใจเกี่ยวกับสิ่งที่คุณอ้างสิทธิ์หรือไม่? คุณสามารถเสนอราคาจากมาตรฐานได้หรือไม่?
oleksijp

@Elliott ดูเหมือนว่าจะเป็นเรื่องจริง มาตรฐาน [17.1.9] ระบุว่า: "อาร์กิวเมนต์เทมเพลตเริ่มต้นอาจถูกระบุในการประกาศเทมเพลต" ไม่ต้อง แต่อาจจะเป็น ดังนั้นฉันจึงไม่เข้าใจว่าทำไมคำตอบอื่น ๆ จึงอ้างว่าควรอยู่ในการประกาศครั้งแรก
oleksijp

และดูเหมือนว่าจะสะดวกกว่ามากที่จะมีค่าเริ่มต้นในนิยาม
oleksijp

8

คุณสามารถประกาศอาร์กิวเมนต์เริ่มต้นสำหรับเทมเพลตได้สำหรับการประกาศเทมเพลตครั้งแรกเท่านั้น หากคุณต้องการอนุญาตให้ผู้ใช้ส่งต่อประกาศเทมเพลตคลาสคุณควรระบุส่วนหัวการส่งต่อ หากคุณต้องการส่งต่อประกาศแม่แบบชั้นเรียนของคนอื่นโดยใช้ค่าเริ่มต้นคุณจะโชคไม่ดี!


เป็นไปได้ที่จะประกาศคลาสที่มีค่าเริ่มต้นที่ระบุไว้ในคำจำกัดความ ดูคำตอบของฉัน
Elliott

ฉันไม่เห็นด้วย. มาตรฐาน says: "แม่แบบพารามิเตอร์จะไม่ได้รับการขัดแย้งเริ่มต้นสองประกาศที่แตกต่างกันอยู่ในขอบเขตเดียวกัน" และฉันไม่พบอะไรเกี่ยวกับค่าเริ่มต้นในการประกาศครั้งแรกเท่านั้น นอกจากนี้รหัสที่มีการประกาศไปข้างหน้าและค่าเริ่มต้นในคำจำกัดความจะรวบรวมและรันได้สำเร็จ คุณแน่ใจเกี่ยวกับสิ่งที่คุณอ้างสิทธิ์หรือไม่? คุณสามารถเสนอราคาจากมาตรฐานได้หรือไม่?
oleksijp

4

คุณสามารถประกาศคลาสเท็มเพลตซึ่งนิยามระบุอาร์กิวเมนต์เริ่มต้น แต่เมื่อใดก็ตามที่คุณอ้างอิงคลาสคุณต้องรวมอาร์กิวเมนต์ทั้งหมดไว้จนกว่าจะมีการกำหนดนิยาม

เช่น. มาใช้std::vectorโดยไม่รวมมัน (อาร์กิวเมนต์ที่สองของstd::vectorถูกกำหนดด้วยค่าเริ่มต้น):

namespace std
{
    template<typename, typename>
    class vector;
}

#include <iostream>

template <typename S, typename T>
void Foo (const std::vector<S,T> & vector)
{
    std::cout << "do vector stuff, eg., display size = "
        << vector.size() << std::endl;
}

template <typename T>
void Foo (const T & t)
{
    std::cout << "do non-vector stuff..." << std::endl;
}

จากนั้นเราสามารถใช้มันได้โดยไม่ต้องรวมเวกเตอร์เช่น:

int main ()
{
    Foo(3);
}

... หรือสามารถใช้กับ std::vectorเช่น:

#include <vector>

// Now the compiler understands how to handle
// std::vector with one argument
// (making use of its default argument)

int main ()
{
    Foo(std::vector<int>(3));
}

ฉันยังไม่ได้ตรวจสอบมาตรฐาน แต่งานนี้บนclang/ gccกับ-std=c++98ขึ้นไป-std=c++17ดังนั้นถ้ามันไม่ได้เป็นอย่างเป็นทางการมาตรฐานแล้วมันดูเหมือนจะเป็นอย่างไม่เป็นทางการเพื่อให้


Foo<> foo;บางทีคุณอาจจะลืมวงเล็บมุมที่ว่างเปล่า
oleksijp
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.