कम से कम महंगे तर्क प्रकार को निर्धारित करने का एक संकलन समय तरीका


15

मेरे पास एक टेम्पलेट है जो इस तरह दिखता है

template <typename T> class Foo
{
public:
    Foo(const T& t) : _t(t) {}
private:
    const T _t;
};

क्या उन मामलों में एक कॉन्स्ट रेफरेंस का उपयोग करने से बचने के लिए एक सामान्य टेम्पलेट मेटाप्रोग्रामिंग तरीका है जहां तर्क प्रकार एक बूल या चार की तरह तुच्छ है? पसंद:

Foo(stl::smarter_argument<T>::type t) : _t(t) {}

1
मैं इसके बारे में चिंता नहीं करेगा, यदि फ़ंक्शन छोटा है तो संकलक इसे इनलाइन करेगा और संदर्भ भी मौजूद नहीं होगा। यदि फंक्शन बड़ा है तो रेफरेंस में पूर्णांक को लपेटने की लागत बहुत कम होगी
एलन बर्टल्स

1
मैं सही अग्रेषण के बारे में अधिक चिंता करूँगा फिर छोटे डेटा प्रकारों पर संदर्भों से बचना। मैं अनुमान लगा रहा हूं कि अधिकांश मामलों में आर-मान संदर्भ से गुजरना पास-दर-मूल्य के लिए अनुकूलित किया जा सकता है।
सुपर

कुछ बातों को ध्यान में रखते हुए, उत्तरों में इंगित नहीं किया गया: आप जो कर रहे हैं वह अंतर्निहित कटौती गाइड को हरा देगा। यदि आप वर्ग टेम्पलेट तर्क कटौती के लिए काम कर रहे हैं, तो आपको एक स्पष्ट कटौती गाइड लिखना याद रखना चाहिए Foo
ब्रायन

जवाबों:


13

मुझे लगता है कि सही प्रकार का गुण है is_scalar । यह निम्नानुसार काम करेगा:

template<class T, class = void>
struct smarter_argument{
    using type = const T&;
};

template<class T>
struct smarter_argument<T, std::enable_if_t<std::is_scalar_v<T>>> {
    using type = T;
};

संपादित करें:

ऊपर अभी भी थोड़ा पुराना स्कूल है, धन्यवाद @HolyBlackCat मुझे इस और अधिक संक्षिप्त संस्करण की याद दिलाने के लिए:

template<class T>
using smarter_argument_t = std::conditional_t<std::is_scalar_v<T>, T, const T&>;

यह is_fundamentalभी काम नहीं करेगा ?
तारेक दकरान

2
@TarekDakhran स्केलर में पॉइंटर्स और एनम शामिल हैं जो मौलिक नहीं हैं, जिन्हें मान IMO द्वारा पारित किया जाना चाहिए।
एलएफ

मैं वर्ग = शून्य वाक्य-विन्यास से परिचित नहीं हूँ। इसका मतलब यह है कि यह कुछ भी हो सकता है क्योंकि इसे अनदेखा किया गया है?
गप्प

1
= voidइसका मतलब है कि यह एक डिफ़ॉल्ट प्रकार है जो शून्य है, इसलिए इसका उपयोग smarter_argument<T>वास्तव में है smarter_argument<T, void>। मैंने इस तर्क के लिए एक नाम छोड़ दिया क्योंकि हमें इसकी आवश्यकता नहीं है, इसलिए class = voidबिना नाम के। यह महत्वपूर्ण है कि std::enable_if_tयदि यह सक्षम है, तो डिफ़ॉल्ट प्रकार के मिलान के लिए भी इसे शून्य होना चाहिए।
n314159

2
को सरल बनाया जा सकता है template <typename T> using smarter_argument = std::conditional_t<std::is_scalar_v<T>, T, const T &>;
होलीब्लैककैट

3

मैं उपयोग करने का सुझाव देता हूं sizeof(size_t)(या sizeof(ptrdiff_t)) जो आपकी मशीन से संबंधित "विशिष्ट" आकार देता है इस उम्मीद के साथ कि इस आकार का कोई भी चर एक रजिस्टर में फिट बैठता है। उस स्थिति में आप इसे सुरक्षित रूप से मान से पास कर सकते हैं। इसके अलावा, जैसा कि @ n314159 ने सुझाव दिया है (इस पोस्ट के अंत में टिप्पणियां देखें) यह सुनिश्चित करना उपयोगी है कि चर भी है trivialy_copyable

यहाँ एक C ++ 17 डेमो है:

#include <array>
#include <ccomplex>
#include <iostream>
#include <type_traits>

template <typename T>
struct maybe_ref
{
  using type = std::conditional_t<sizeof(T) <= sizeof(size_t) and
                                  std::is_trivially_copyable_v<T>, T, const T&>;
};

template <typename T>
using maybe_ref_t = typename maybe_ref<T>::type;

template <typename T>
class Foo
{
 public:
  Foo(maybe_ref_t<T> t) : _t(t)
  {
    std::cout << "is reference ? " << std::boolalpha 
              << std::is_reference_v<decltype(t)> << std::endl;
  }

private:
  const T _t;
};

int main()
{
                                                          // with my machine
  Foo<std::array<double, 1>> a{std::array<double, 1>{}};  // <- by value
  Foo<std::array<double, 2>> b{std::array<double, 2>{}};  // <- by ref

  Foo<double>               c{double{}};                // <- by value
  Foo<std::complex<double>> d{std::complex<double>{}};  // <- by ref
}

ध्यान दें कि "आपकी मशीन का सूचक आकार" जैसी कोई चीज नहीं है। उदाहरण के लिए इसे चलाएं : struct Foo { void bar(){ }; int i; }; std::cout << sizeof(&Foo::i) << std::endl; //prints 8 std::cout << sizeof(&Foo::bar) << std::endl; //prints 16
BlueTune

@BlueTune दिलचस्प, टिप्पणी के लिए धन्यवाद। इसके अलावा stackoverflow.com/a/6751914/2001017 को अपने उदाहरण के रूप में देखें : संकेत और फ़ंक्शन पॉइंटर्स के अलग-अलग आकार हो सकते हैं। यहां तक ​​कि विभिन्न बिंदुओं के अलग-अलग आकार हो सकते हैं। मशीन का "विशिष्ट" आकार प्राप्त करने का विचार था। मैंने
साइज़ोफ़

1
@Picaud शायद आप <=इसके बजाय उपयोग करना चाहते हैं ==, अधिकांश मशीनों पर आपका वर्तमान कोड charसंदर्भ द्वारा उदाहरण के लिए लेता है अगर मुझे वह अधिकार दिखाई देता है।
n314159

2
तुम भी Tमामूली नकल होने के लिए जाँच करना चाहते हो सकता है । उदाहरण के लिए एक साझा पॉइंटर size_tमेरे प्लैटफॉर्म पर केवल दो बार का आकार है और इसे केवल एक पॉइंटर के साथ लागू किया जा सकता है, इसे उसी आकार में नीचे लाया जा सकता है। लेकिन आप निश्चित रूप से कास्ट रेफरी द्वारा शेयर_पार्ट लेना चाहते हैं न कि वैल्यू के हिसाब से।
n314159

@ n314159 हाँ यह एक सुधार होगा। यदि आप मेरे उत्तर में अपने विचार को शामिल करते हैं तो क्या आप ठीक हैं?
पिकाउड विंसेंट

2

मैं C ++ 20 कीवर्ड का उपयोग करूंगा requires। बस असे ही:

#include <iostream>

template<typename T>
class Foo
{
public:
    Foo(T t) requires std::is_scalar_v<T>: _t{t} { std::cout << "is scalar" <<std::endl; }
    Foo(const T& t) requires (not std::is_scalar_v<T>): _t{t} { std::cout << "is not scalar" <<std::endl;}
private:
    const T _t;
};

class cls {};

int main() 
{
    Foo{true};
    Foo{'d'};
    Foo{3.14159};
    cls c;
    Foo{c};

    return 0;
}

निम्नलिखित आउटपुट देखने के लिए आप कोड को ऑनलाइन चला सकते हैं :

is scalar
is scalar
is scalar
is not scalar

दिलचस्प। क्या कास्ट ऑटो और कंस्ट्रक्टर तर्क के लिए उपयोग करने का कोई लाभ है?
गप्प

@cppguy: मुझे खुशी है कि आप यह सवाल पूछ रहे हैं। अगर मैं "const auto & t" के तर्क को "const T & t" से बदल दूं तो कोड संकलित नहीं होगा। त्रुटि "फू ..." के टेम्पलेट तर्कों के लिए अस्पष्ट कटौती पढ़ती है। शायद आपको पता चल जाए कि क्यों?
ब्लूटन

1
@cppguy: हमारी चर्चा के परिणामस्वरूप एक प्रश्न सामने आया। आप इसे यहाँ पा सकते हैं ।
ब्लू ट्यून

1
अवधारणाएं यहां ओवरकिल है और विकल्प की तुलना में पढ़ने के लिए काफी कठिन है।
एसएस ऐनी

1
@SS ऐनी: C ++ 20 अवधारणाओं का उपयोग करने वाला IMHO कभी भी ओवरकिल नहीं होता है। यह सिर्फ सुरुचिपूर्ण है। IMHO के विकल्प मैंने अब तक पढ़े हैं, क्योंकि पढ़ना मुश्किल है, क्योंकि नेस्टेड टेम्प्लेट का उपयोग किया जाता है।
ब्लू ट्यून
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.