আমি কেন টেমপ্লেট প্যারামিটার হিসাবে ভাসমান মান ব্যবহার করতে পারি না?


120

আমি যখন floatটেমপ্লেট প্যারামিটার হিসাবে ব্যবহার করার চেষ্টা করি তখন সংকলকটি এই কোডটির জন্য কাঁদে, যখন intকাজ করে ভাল।

এটি কি কারণ আমি floatটেমপ্লেট প্যারামিটার হিসাবে ব্যবহার করতে পারি না ?

#include<iostream>
using namespace std;

template <class T, T defaultValue>
class GenericClass
{
private:
    T value;
public:
    GenericClass()
    {
        value = defaultValue;
    }

    T returnVal()
    {
        return value;
    }
}; 


int main()
{
    GenericClass <int, 10> gcInteger;
    GenericClass < float, 4.6f> gcFlaot;

    cout << "\n sum of integer is "<<gcInteger.returnVal();
    cout << "\n sum of float is "<<gcFlaot.returnVal();

    return 0;       
}

ত্রুটি:

main.cpp: In function `int main()':
main.cpp:25: error: `float' is not a valid type for a template constant parameter
main.cpp:25: error: invalid type in declaration before ';' token

main.cpp:28: error: request for member `returnVal' in `gcFlaot',
                    which is of non-class type `int'

আমি রন পেন্টনের "গেম প্রোগ্রামার্সের জন্য ডেটা স্ট্রাকচারস" পড়ছি , লেখক পাস করেছেন float, তবে আমি যখন চেষ্টা করে দেখি তখন এটি সংকলিত হয় না।


1
লেখক কি সত্যিই floatএকটি নন-টাইপ টেম্পলেট প্যারামিটার হিসাবে ব্যবহার করেন ? কোন অধ্যায়ে এটি?
কে-বালো

1
এটি পাওয়া গেছে, এটি "টেমপ্লেট প্যারামিটার হিসাবে মানগুলি ব্যবহার করা" এ ...
কে-বেলো

উত্তর:


37

বর্তমান সি ++ স্ট্যান্ডার্ডটি float(যেমন আসল সংখ্যা) বা অক্ষর স্ট্রিং লিটারেলগুলিকে টেম্পলেট অ-টাইপ পরামিতি হিসাবে ব্যবহার করার অনুমতি দেয় না । আপনি অবশ্যই সাধারণ আর্গুমেন্ট হিসাবে floatএবং char *প্রকারগুলি ব্যবহার করতে পারেন ।

সম্ভবত লেখক এমন একটি সংকলক ব্যবহার করছেন যা বর্তমান মানটিকে অনুসরণ করে না?


8
দয়া করে মানক থেকে প্রাসঙ্গিক বিভাগটির লিঙ্ক বা অনুলিপি সরবরাহ করুন
থোকোশম্যান

2
@ থেকোশম্যান প্রমিতের প্রাসঙ্গিক বিভাগ + আরও তথ্যের আমার (নতুন পোস্ট করা) উত্তরে উপলব্ধ।
ফিলিপ রোজন -

1
সি ++ ১১-এ, টেমপ্লেট অ-টাইপ পরামিতি হিসাবে অক্ষরের স্ট্রিং আক্ষরিক ব্যবহার সম্ভব। যদি আপনার টেমপ্লেট একটি অক্ষর প্যাক নেয় template<char ...cs>, তবে স্ট্রিং আক্ষরিক সংকলন সময়ে এই জাতীয় প্যাক রূপান্তর করা যেতে পারে। আদর্শের উপর একটি ডেমো এখানে । (ডেমোটি সি ++ ১৪, তবে এটি আবার সি ++ 11 এ পোর্ট করা সহজ - std::integer_sequenceএকমাত্র অসুবিধা)
অ্যারন ম্যাকডেইড

মনে রাখবেন যে আপনি char &*অন্য কোথাও আক্ষরিক সংজ্ঞা দিলে আপনি একটি টেম্পলেট প্যারামিটার হিসাবে ব্যবহার করতে পারেন । একটি workaround হিসাবে বেশ ভাল কাজ করে।
স্টেনসফট

137

সহজ উত্তর

স্ট্যান্ডার্ডটি নন-টাইপ টেম্পলেট-আর্গুমেন্ট হিসাবে ভাসমান পয়েন্টগুলিকে অনুমতি দেয় না , যা সি ++ 11 স্ট্যান্ডার্ডের নিম্নলিখিত বিভাগে পড়তে পারে;

14.3.2 / 1 টেমপ্লেট নন-টাইপ আর্গুমেন্ট [temp.arg.nontype]

অ-টাইপযুক্ত, নন-টেম্পলেট টেম্পলেট-প্যারামিটারের জন্য একটি টেম্পলেট-যুক্তি হতে হবে:

  • অবিচ্ছেদ্য বা গণনা প্রকারের একটি অ-টাইপ টেম্পলেট-প্যারামিটারের জন্য, টেমপ্লেট-প্যারামিটারের ধরণের রূপান্তরিত ধ্রুবক অভিব্যক্তি (5.19);

  • একটি অ-টাইপ টেম্পলেট-প্যারামিটারের নাম; অথবা

  • অবিচ্ছিন্ন অভিব্যক্তি (৫.১৯) যা স্থিতিশীল স্টোরেজ সময়কাল এবং বাহ্যিক বা অভ্যন্তরীণ সংযোগ বা কোনও ফাংশন টেম্পলেট এবং ফাংশন টেম্পলেট-আইডিসহ বহিরাগত বা অভ্যন্তরীণ লিঙ্কেজ সহ কোনও ফাংশনের ঠিকানা নির্ধারণ করে তবে অ স্থিত শ্রেণীর সদস্য ব্যতীত (উপেক্ষা করে) বন্ধনী) & আইডি-এক্সপ্রেশন হিসাবে, নাম বাদে বা ফাংশন বা অ্যারে উল্লেখ করে বাদ দেওয়া যেতে পারে এবং সংশ্লিষ্ট টেম্পলেট-প্যারামিটারটি যদি কোনও রেফারেন্স হয় তবে বাদ দেওয়া হবে; অথবা

  • একটি ধ্রুবক অভিব্যক্তি যা নাল পয়েন্টার মানের (4.10) মূল্যায়ন করে; অথবা

  • একটি স্থির অভিব্যক্তি যা নাল সদস্য পয়েন্টার মানের (4.11) মূল্যায়ন করে; অথবা

  • 5.3.1 বর্ণিত হিসাবে সদস্যকে একটি পয়েন্টার।


তবে .. তবে .. কেন !?

এটি সম্ভবত এই কারণে ঘটে যে ভাসমান পয়েন্ট গণনাগুলি সঠিক পদ্ধতিতে উপস্থাপন করা যায় না। যদি এটি অনুমোদিত হয় তবে এটির মতো কিছু করার সময় এটি ভুল / অদ্ভুত আচরণের ফলাফল / হতে পারে;

func<1/3.f> (); 
func<2/6.f> ();

আমরা একই ফাংশনটিকে দু'বার কল করতে চেয়েছিলাম কিন্তু দুটি গণনার ভাসমান পয়েন্ট উপস্থাপনা হুবহু এক হওয়ার নিশ্চয়তা না পাওয়ায় এটি এমনটি হতে পারে না ।


আমি কীভাবে টেমপ্লেট আর্গুমেন্ট হিসাবে ভাসমান পয়েন্ট মান উপস্থাপন করব?

C++11আপনি কিছু চমত্কার উন্নত ধ্রুবক-এক্সপ্রেশন লিখতে পারে সাথে ( কনটেক্সট্রপ) ) যে একটি ভাসমান মান সময় সঙ্কলন লব / হর নিরূপণ করবে এবং তারপর পৃথক পূর্ণসংখ্যা আর্গুমেন্ট হিসাবে এই দুটি পাস।

কিছু প্রান্তিকের সংজ্ঞা দিতে মনে রাখবেন যাতে ভাসমান পয়েন্টের মান একে অপরের কাছাকাছি একই সংখ্যক / ডিনোমিনেটর দেয় , অন্যথায় এটি বিন্দুমাত্র অর্থহীন যেহেতু এটি পূর্বে উল্লিখিত একই ফল ফলবে কারণ ভাসমান পয়েন্টের মানগুলিকে অ-টাইপ হিসাবে অনুমতি না দেওয়ার কারণ হিসাবে পূর্বে উল্লিখিত হয় টেম্পলেট আর্গুমেন্ট


56
সি ++ 11 সমাধানটি <ratio>§20.10 দ্বারা "সংকলন-সময় যুক্তিযুক্ত পাটিগণিত" হিসাবে বর্ণনা করা হয়েছে। যা আপনার উদাহরণ থেকে ডান কাটা।
পটোটোওয়াত্টার

1
@ পোটাটোসওয়টার আফিক এসটিএলে কোনও ফ্লোটকে অংকের সংকেত / ডিনোমিনেটরে রূপান্তর করার কোনও পদ্ধতি নেই <ratio>?
ফিলিপ রোজন -

3
এটি সত্যিই একটি দৃinc় ব্যাখ্যা দেয় না। ভাসমান-বিন্দুর পুরো বিষয়টি হ'ল এটি হুবহু মানগুলি উপস্থাপন করে। আপনার কাছে থাকা সংখ্যার সাথে অন্য কোনও কিছুর সান্নিধ্য হিসাবে বিবেচনা করতে আপনি নির্দ্বিধায় রয়েছেন এবং এটি করা প্রায়শই দরকারী, তবে সংখ্যাগুলি নিজেই সঠিক।
tmyklebu

4
@ ফিলিপরোসেন-রেফপ: সমস্ত ভাসমান-পয়েন্ট সংখ্যা হুবহু। আমার জানা প্রতিটি টার্গেটের উপর ফ্লোটিং-পয়েন্ট পাটিগণিত সু-সংজ্ঞায়িত। বেশিরভাগ ভাসমান-পয়েন্ট অপারেশনগুলি ভাসমান-পয়েন্ট ফলাফল দেয়। আমি কমিটির লক্ষ্য নির্ধারণের সম্ভাব্য-উদ্ভট ভাসমান-পয়েন্ট পাটিগণিত বাস্তবায়নের জন্য জোর করতে চাইনি কমিটির প্রশংসা করতে পারি, তবে আমি বিশ্বাস করি না "গাণিতিকটি পূর্ণসংখ্যার গাণিতিক থেকে পৃথক" ভাসমান-পয়েন্ট টেম্পলেট যুক্তি নিষেধ করার একটি ভাল কারণ is দিনের শেষে এটি একটি স্বেচ্ছাসেবী বাধা।
tmyklebu

5
@ আইহেনি: মান কি 12345 * 12345বলে? (এটি কোনওint স্বাক্ষরিত
ইন্টারের

34

এটি সীমাবদ্ধতা হবার কারণগুলির মধ্যে কেবল একটি কারণ সরবরাহ করতে (অন্তত বর্তমান মানদণ্ডে)।

টেমপ্লেট বিশেষীর সাথে মিলে গেলে, সংকলকটি নন-টাইপ আর্গুমেন্ট সহ টেম্পলেট আর্গুমেন্টের সাথে মেলে।

তাদের প্রকৃতির দ্বারা, ভাসমান পয়েন্টের মানগুলি সঠিক নয় এবং তাদের প্রয়োগটি সি ++ স্ট্যান্ডার্ড দ্বারা নির্দিষ্ট করা হয়নি। ফলস্বরূপ, দুটি ভাসমান পয়েন্ট নন-টাইপ আর্গুমেন্টগুলি সত্যই কখন মিলবে তা নির্ধারণ করা কঠিন:

template <float f> void foo () ;

void bar () {
    foo< (1.0/3.0) > ();
    foo< (7.0/21.0) > ();
}

এই অভিব্যক্তিগুলি অগত্যা একই "বিট প্যাটার্ন" উত্পাদন করে না এবং তাই এটি আবশ্যক যে কোনও শব্দবস্তু ছাড়াই - তারা একই বিশেষত্বটি ব্যবহার করেছিল তার গ্যারান্টি দেওয়া সম্ভব হবে না।


16
ভাষা থেকে সম্পূর্ণরূপে ভাসমান নিষিদ্ধ করার পক্ষে এটি প্রায় একটি যুক্তি। অথবা, সর্বনিম্ন, ==অপারেটরটিকে নিষিদ্ধ করুন :-) আমরা ইতিমধ্যে রানটাইমে এই অযৌক্তিকতাটি মেনে নিয়েছি, সংকলনের সময়ও কেন নয়?
অ্যারন ম্যাকডেইড

3
@ অ্যারোন এমসিডেইডের সাথে একমত হোন, এটি কোনও আর্গুমেন্টের বেশি নয়। সুতরাং আপনি সংজ্ঞা সাবধান করা প্রয়োজন। তাতে কি? যতক্ষণ না এটি ধ্রুবকগুলির কাছ থেকে পাওয়া জিনিসগুলির জন্য কাজ করে, এটি ইতিমধ্যে বেশ উন্নতি।
einpoklum

1
সি ++ ২০ এখন নন-টাইপ টেম্পলেট প্যারামিটার হিসাবে ভাসমান (অন্য কোনও অবজেক্টের ধরণের) জন্য অনুমতি দেয়। তবুও সি ++ 20 ফ্লোট বাস্তবায়ন নির্দিষ্ট করে না। এটি দেখায় যে আইনপোক্লাম এবং হারুনের একটি বিন্দু রয়েছে।
আন্দ্রেয়াস এইচ।

20

প্রকৃতপক্ষে, আপনি টেমপ্লেট পরামিতি হিসাবে ভাসমান আক্ষরিক ব্যবহার করতে পারবেন না। বিভাগ ১৪.১ দেখুন ("একটি নন-টাইপ টেম্পলেট-প্যারামিটারের মধ্যে নিম্নলিখিতগুলির মধ্যে একটি (allyচ্ছিকভাবে সিভি-কোয়ালিটিভড) প্রকার থাকতে হবে ...") স্ট্যান্ডার্ডের ।

আপনি টেমপ্লেট প্যারামিটার হিসাবে ফ্লোটের রেফারেন্স ব্যবহার করতে পারেন:

template <class T, T const &defaultValue>
class GenericClass

.
.

float const c_four_point_six = 4.6; // at global scope

.
.

GenericClass < float, c_four_point_six> gcFlaot;

11
আপনি পারেন। কিন্তু এটি একই জিনিস না। আপনি সংকলন-সময় ধ্রুবক হিসাবে রেফারেন্স ব্যবহার করতে পারবেন না।

12

কনটেক্সার্স হিসাবে প্যারামিটারগুলি তাদের নিজস্ব শ্রেণিতে মুড়ে দিন rap কার্যকরভাবে এটি একটি বৈশিষ্ট্যের সাথে সমান কারণ এটি ফ্লোটের সেট দিয়ে ক্লাসকে প্যারামিটারাইজ করে।

class MyParameters{
    public:
        static constexpr float Kd =1.0f;
        static constexpr float Ki =1.0f;
        static constexpr float Kp =1.0f;
};

এবং তারপরে ক্লাসের ধরণটিকে পরামিতি হিসাবে গ্রহণ করে একটি টেম্পলেট তৈরি করুন

  template <typename NUM, typename TUNING_PARAMS >
  class PidController {

      // define short hand constants for the PID tuning parameters
      static constexpr NUM Kp = TUNING_PARAMS::Kp;
      static constexpr NUM Ki = TUNING_PARAMS::Ki;
      static constexpr NUM Kd = TUNING_PARAMS::Kd;

      .... code to actually do something ...
};

এবং তারপরে এটি ব্যবহার করুন ...

int main (){
    PidController<float, MyParameters> controller;
    ...
    ...
}

এটি কম্পাইলারকে গ্যারান্টি দেয় যে একই প্যারামিটার প্যাকের সাথে প্রতিটি টেম্পলেট ইনস্ট্যান্টেশনের জন্য কোডের একক উদাহরণ তৈরি করা হয়। এটি সমস্ত সমস্যার সমাধান করে এবং আপনি টেম্প্লেটেড ক্লাসের অভ্যন্তরে কনফেসপ্রস হিসাবে ভাসমান এবং ডাবল ব্যবহার করতে সক্ষম হন।


5

আপনি যদি টাইপ প্রতি স্থির পূর্বনির্ধারিত ঠিক থাকেন তবে আপনি ধ্রুবক হিসাবে এটি সংজ্ঞায়িত করতে এবং প্রয়োজনীয় হিসাবে এটি বিশেষজ্ঞ করতে একটি টাইপ তৈরি করতে পারেন।

template <typename T> struct MyTypeDefault { static const T value; };
template <typename T> const T MyTypeDefault<T>::value = T();
template <> struct MyTypeDefault<double> { static const double value; };
const double MyTypeDefault<double>::value = 1.0;

template <typename T>
class MyType {
  public:
    MyType() { value = MyTypeDefault<T>::value; }
  private:
    T value;
 };

আপনার যদি সি ++ 11 থাকে তবে আপনি ডিফল্ট মান নির্ধারণের সময় কনটেক্সপ্র ব্যবহার করতে পারেন। সি ++ ১৪ এর সাথে, মাইটাইপডিফল্ট একটি টেম্পলেট ভেরিয়েবল হতে পারে যা সিনট্যাক্টিকভাবে কিছুটা পরিষ্কার।

//C++14
template <typename T> constexpr T MyTypeDefault = T();
template <> constexpr double MyTypeDefault<double> = 1.0;

template <typename T>
class MyType {
  private:
    T value = MyTypeDefault<T>;
 };

2

অন্যান্য উত্তরগুলি আপনি সম্ভবত ভাসমান পয়েন্ট টেম্পলেট প্যারামিটারগুলি চান না কেন তার সঠিক কারণ দেয় তবে সত্যিকারের চুক্তির ব্রোকার আইএমও হ'ল '==' ব্যবহার করে এবং সামান্য দিকের সাম্যতা এক নয়:

  1. -0.0 == 0.0, কিন্তু 0.0এবং-0.0 সমান নয়

  2. NAN != NAN

উভয় ধরণের সাম্যই টাইপ সাম্যতার জন্য ভাল ক্যানসিডেট নয়: অবশ্যই পয়েন্ট ২ ==টাইপ সাম্যতা নির্ধারণের জন্য অবৈধ ব্যবহার করে । এর পরিবর্তে কেউ বিটওয়াইজ সমতা ব্যবহার করতে পারে তবে x != yতার অর্থ বোঝায় না MyClass<x>এবং MyClass<y>এটি বিভিন্ন ধরণের (২. দ্বারা), যা অদ্ভুত হবে।


1

আপনি সর্বদা এটি নকল করতে পারেন ...

#include <iostream>

template <int NUM, int DEN>
struct Float
{
    static constexpr float value() { return (float)NUM / (float)DEN; }
    static constexpr float VALUE = value();
};

template <class GRAD, class CONST>
struct LinearFunc
{
    static float func(float x) { return GRAD::VALUE*x + CONST::VALUE; }
};


int main()
{
    // Y = 0.333 x + 0.2
    // x=2, y=0.866
    std::cout << " func(2) = "
              << LinearFunc<Float<1,3>, Float<1,5> > ::func(2) << std::endl;
}

তথ্যসূত্র: http://code-slim-jim.blogspot.jp/2013/06/c11-no-floats-in-templates-wtf.html


3
float! = যুক্তিযুক্ত সংখ্যা। দুটি খুব পৃথক ধারণা। একটি ম্যান্টিসার মাধ্যমে গণনা করা হয় এবং একটি ঘনিষ্ঠ হিসাবে, অন্যটি ভাল, একটি যুক্তিযুক্ত - প্রতিটি যুক্তি দ্বারা প্রতিনিধিত্বযোগ্য নয় একটি দ্বারা প্রতিনিধিত্বযোগ্য float
রিচার্ড জে রস তৃতীয়

2
@ রিচার্ডজে.রোসআইআইআই floatখুব অবশ্যই একটি যুক্তিযুক্ত সংখ্যা, তবে এমন কিছু রয়েছে floatযা দুটি সংখ্যার অনুপাত হিসাবে প্রতিনিধিত্বযোগ্য নয় int। ম্যান্টিসাটি একটি পূর্ণসংখ্যা এবং 2 ^ সূচকটি একটি পূর্ণসংখ্যা
কালেথ

1

সংকলন-সময় ধ্রুবক হতে যদি আপনার দ্বিগুণ প্রয়োজন না হয় তবে আপনি এটি পয়েন্টার হিসাবে পাস করতে পারেন:

#include <iostream>

extern const double kMyDouble = 0.1;;

template <const double* MyDouble>
void writeDouble() {
   std::cout << *MyDouble << std::endl; 
}

int main()
{
    writeDouble<&kMyDouble>();
   return 0;
}

একটি রেফারেন্স সম্ভবত আরও ভাল, @ ম্যানশোডোর উত্তর দেখুন
einpoklum ২

1
সংকলনের সময় এটি কি যথাযথভাবে হ্রাস পাবে?
Ant6n

1

সি ++ 20 দিয়ে শুরু করা এটি সম্ভব

এটি মূল প্রশ্নের উত্তরও দেয়:

Why can't I use float value as a template parameter?

কারণ কেউ এখনও এটি স্ট্যান্ডার্ডে প্রয়োগ করেনি। এর কোন মৌলিক কারণ নেই।

সি ++ ২০-এ নন-টাইপ টেম্পলেট প্যারামিটারগুলি এখন ভাসমান এবং এমনকি শ্রেণীর অবজেক্ট হতে পারে।

শ্রেণীর অবজেক্টগুলির জন্য কিছু প্রয়োজনীয়তা রয়েছে (সেগুলি অবশ্যই আক্ষরিক ধরণের হওয়া উচিত ) এবং ব্যবহারকারী হিসাবে সংজ্ঞায়িত অপারেটর হিসাবে রোগগত ক্ষেত্রে বাদ দেওয়ার জন্য কিছু অন্যান্য প্রয়োজনীয়তা পূরণ করে == ( বিশদ ) ।

আমরা এমনকি ব্যবহার করতে পারেন auto

template <auto Val>
struct Test {
};

struct A {};
static A aval;
Test<aval>  ta;
Test<A{}>  ta2;
Test<1.234>  tf;
Test<1U>  ti;

নোট করুন যে জিসিসি 9 (এবং 10) ক্লাস নন-টাইপ টেম্পলেট প্যারামিটারগুলি প্রয়োগ করে, তবে এখনও ভাসমানদের জন্য নয়


0

আপনি যদি কেবলমাত্র একটি নির্দিষ্ট নির্ভুলতা উপস্থাপন করতে চান তবে আপনি একটি ফ্লোট প্যারামিটারকে একটি ইনটে রূপান্তর করতে এর মতো প্রযুক্তি ব্যবহার করতে পারেন।

উদাহরণস্বরূপ, যথাক্রমে 2 ডিজিট (100 দ্বারা বিভাজক) অনুমান করে নিম্নলিখিত হিসাবে 1.75 এর বৃদ্ধির ফ্যাক্টর সহ একটি অ্যারে তৈরি করা যেতে পারে।

template <typename _Kind_, int _Factor_=175>
class Array
{
public:
    static const float Factor;
    _Kind_ * Data;
    int Size;

    // ...

    void Resize()
    {
         _Kind_ * data = new _Kind_[(Size*Factor)+1];

         // ...
    }
}

template<typename _Kind_, int _Factor_>
const float Array<_kind_,_Factor_>::Factor = _Factor_/100;

আপনি যদি টেমপ্লেট আর্গুমেন্ট তালিকায় 1.75 এর 175 এর উপস্থাপনাটি পছন্দ না করেন তবে আপনি সর্বদা এটি কোনও ম্যাক্রোতে মোড়ানো করতে পারেন।

#define FloatToIntPrecision(f,p) (f*(10^p))

template <typename _Kind_, int _Factor_=FloatToIntPrecision(1.75,2)>
// ...

এটি ...::Factor = _Factor_/100.0;অন্যথায় হওয়া উচিত এটি পূর্ণসংখ্যা বিভাগ হবে।
alfC
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.