วิธีคืนข้อมูลประเภทที่ถูกต้องในแม่แบบ?


9
#include <iostream>
using namespace std;

template <class X, class Y>
Y big(X a, Y b)
{
   if (a > b)
      return (a);
   else return (b);
}

int main()
{
   cout << big(32.8, 9);
}

นี่ฉันกำลังใช้แม่แบบใน CPP ดังนั้นเมื่อผมเรียกใช้ฟังก์ชันbigผ่านการขัดแย้งของdoubleและประเภทผมต้องการคำตอบกลับมาซึ่งเป็นint doubleประเภทของที่นี่ก็จะส่งกลับแทน3232.8

ฉันจะได้รับผลลัพธ์ที่ต้องการได้อย่างไร จะเขียนbigฟังก์ชั่นการส่งคืนที่เหมาะสมได้อย่างไร?


1
ฟังก์ชั่นสามารถคืนค่าคงที่ได้เพียงประเภทเดียวเท่านั้น คุณไม่สามารถเลือกได้ว่าจะส่งคืนเมื่อใด
Jesper Juhl

1
คุณอาจต้องการดูวิธีstd::maxการใช้งาน ต้องทราบชนิดการคืนค่าของฟังก์ชันในเวลารวบรวมใน C ++ ดังนั้นคุณไม่สามารถมีชนิดส่งคืนนี้ขึ้นอยู่กับค่ารันไทม์ของพารามิเตอร์ของคุณ นี่คือสาเหตุที่ฟังก์ชั่นดังกล่าวคุณต้องการพารามิเตอร์ทั้งสองเพื่อให้มีประเภทเดียวกัน (เช่นมีประเภท X แต่ไม่ใช่ Y)
Boris Dalstein

คำตอบ:


12

ฟังก์ชั่นสามารถมีชนิดส่งคืนได้เพียงประเภทเดียวเท่านั้นที่จะต้องทราบในเวลารวบรวม อย่างไรก็ตามคุณสามารถใช้std::common_typeเพื่อส่งคืนชนิดที่พารามิเตอร์ทั้งสองสามารถแปลงเป็นนัยได้

นั่นจะเป็น

#include <type_traits>
template <class X, class Y>
typename std::common_type<X,Y>::type big(X a, Y b)
{
   if (a > b)
      return a;
   else return b;
}

และเพื่อตรวจสอบว่ามันส่งกลับจริงdoubleเมื่อผ่านintและdoubleเราสามารถทำ:

int main() {
    auto x = big(4.2,42);
    std::cout << std::is_same<decltype(x),double>::value;
}

พิมพ์ไหน

1

PS: std::common_typeสามารถใช้ผู้ประกอบการที่สามด้านหลัง scences และเป็นวิธีการแก้ปัญหานี้ไม่แตกต่างจากคำตอบอื่น ๆ ( auto+ ternary) พลังที่แท้จริงของstd::common_typeมันคือมันยอมรับพารามิเตอร์จำนวนเท่าใดก็ได้


10

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

template <typename X, typename Y>
auto big(X&& a, Y&& b) -> decltype(a > b ? a : b) // ---> like this
{
   return  a > b ? a : b;
}

ดูการถ่ายทอดสด


อย่างไรก็ตามหากคุณมีสิทธิ์เข้าถึง หรือสูงกว่าautoก็เพียงพอแล้วเนื่องจากคอมไพเลอร์จะสรุปประเภทที่ถูกต้องหากคุณใช้พร้อมกับโอเปอเรเตอร์ที่มีเงื่อนไขดังนี้:

template <typename X, typename Y>
auto big(X a, Y b)
{
   return  a > b ? a : b;
}

ดูการถ่ายทอดสด


ไม่จำเป็นต้องมีชนิดส่งคืนตามมาอย่างน้อยต้องเป็น C ++ 14
sweenish

@ วอลนัตจุดดี อีกหนึ่งตัวเลือกคือการอ้างอิงการส่งต่อ?
JeJo

1
@JeJo ใช่ฉันคิดว่ามันดีเหมือนกัน แต่อาจไม่มีจุดหมายเพราะคุณไม่ได้แก้ไขอาร์กิวเมนต์อย่างใดอย่างหนึ่งและประเภทการส่งคืนจะยังเป็นการอ้างอิง lvalue ในกรณีใดกรณีหนึ่ง (แม้ว่าอาจไม่ใช่ - const)
วอลนัท

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

หากมีคนดูรหัสของคุณดูเหมือนว่าพารามิเตอร์ที่ส่งผ่านจะตัดสินใจว่าจะส่งคืนประเภทใดที่ใครบางคนจะได้รับซึ่งไม่ใช่ตัวอักษร! คุณจะกลับมาเป็นสองเท่าเสมอแม้ว่า a จะใหญ่กว่า b
Klaus

4

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

#include <iostream>

template <typename X, typename Y>
decltype(auto) big(const X& a, const Y& b)  // return type can just be auto as well 
{
    return a > b ? a : b;
}

int main()
{
    std::cout << big(32.8, 9) << '\n';
    std::cout << big(9, 32.8) << '\n';
    std::cout << big(32.8, 90) << '\n';
    std::cout << big(90, 32.8) << '\n';
}

สิ่งนี้จะพิมพ์ค่าที่ถูกต้องทั้งสี่ไปยังหน้าจอ

https://godbolt.org/z/fyGsmo

สิ่งหนึ่งที่สำคัญที่ควรทราบคือสิ่งนี้จะใช้ได้กับประเภทที่สามารถเปรียบเทียบกันได้เท่านั้นเช่นคอมไพเลอร์จะแปลงประเภทหนึ่งเป็นอีกประเภทโดยนัยเพื่อการเปรียบเทียบ

สำคัญ : พารามิเตอร์จะต้องดำเนินการโดยการอ้างอิงเพื่อหลีกเลี่ยงพฤติกรรมที่ไม่ได้กำหนด สิ่งนี้เกี่ยวข้องกับประเภทผลตอบแทนที่ฉันติดอยู่อย่างดื้อรั้น decltype(auto)สามารถส่งคืนการอ้างอิงถึงประเภท หากคุณส่งคืนบางสิ่งในเครื่องไปยังฟังก์ชัน (นับจำนวนอาร์กิวเมนต์) คุณจะได้รับพฤติกรรมที่ไม่ได้กำหนด


@ วอลนัตโดยบังเอิญการส่งคืนข้อมูลอ้างอิงนั้นยากกว่าเว็บไซต์นี้มาก แต่ก็ควรที่จะรู้เกี่ยวกับพฤติกรรมที่ไม่ได้กำหนด ไม่ใช่ว่านี่จะเป็นรหัสที่ฉันเขียนอยู่ดี มันเป็นคำตอบสำหรับคำถาม
สวีดิช

1
อา. ฉันอ่านความคิดเห็นก่อนหน้าของคุณว่าเป็นสองจุดที่แตกต่างกันและไม่มีผลและสาเหตุ ฉันสามารถแก้ไขได้อย่างเหมาะสม
ขนมหวาน

ฉันได้เพิ่มข้อจำกัดความรับผิดชอบเป็นพิเศษ
สวีดิช

2

นี่ไม่ใช่ทางออกที่ถูกต้องสำหรับสถานการณ์ที่แม่นยำของคุณในทุกโอกาส - คำตอบอื่น ๆ น่าจะใกล้เคียงกับสิ่งที่คุณต้องการ

แต่ถ้าคุณจริงๆต้องกลับประเภทที่แตกต่างกันอย่างสิ้นเชิงที่รันไทม์ด้วยเหตุผลบางอย่างวิธีที่ถูกต้อง (ตั้งแต่ ) คือการใช้std::variantซึ่งเป็นประเภทของสหภาพชนิดปลอดภัย

#include <variant>

template <typename X, typename Y>
std::variant<X, Y> max(X a, Y b) {
  if (a > b)
    return std::variant<X, Y>(std::in_place_index_t<0>, a);
  else
    return std::variant<X, Y>(std::in_place_index_t<1>, b);
}

โปรดทราบว่าจากนั้นความรับผิดชอบอยู่บนผู้โทรเพื่อจัดการกับค่าที่ส่งคืนส่วนใหญ่มีแนวโน้มที่จะใช้std::visitหรือไม่ชอบ


-2

มันจะคืนค่า int เพราะ Y เป็น int และมันจะร่าย 32.8 ไป เมื่อคุณเรียกว่าใหญ่ 32,82 เป็นทุ่น แต่ 8 คือ int และฟังก์ชั่นกลับมาเป็น Y ซึ่งยังเป็น int

คุณไม่สามารถแก้ไขสิ่งนี้ได้ตามที่คุณจำเป็นต้องรู้ตอนรันไทม์ซึ่งผลตอบแทนประเภทใหญ่ดังนั้นให้ a และ b เป็นประเภทเดียวกันดังนี้:

    #include <iostream>
    using namespace std;

    template <typename X>

    X big (X a, X b)
    {
    if (a>b)
    return a;

    else return b;
    }

    int main()
    {
    cout<< big (32.8, 9.0);
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.