আমি কেন কোনও বৈকল্পিকের সূচকটি পুনরুদ্ধার করতে এবং এটির সামগ্রী পেতে এটি ব্যবহার করতে পারি না?


10

আমি একটি বৈকল্পিকের বিষয়বস্তু অ্যাক্সেস করার চেষ্টা করছি। আমি সেখানে কী জানি না, তবে ধন্যবাদ, বৈকল্পিকটি কী করে। সুতরাং আমি ভেবেছিলাম আমি কেবল বৈকল্পিকটি জিজ্ঞাসা করব এটিতে কোন সূচক রয়েছে এবং তারপরে সেই সূচিটি std::getতার সামগ্রীতে ব্যবহার করব।

তবে এটি সংকলন করে না:

#include <variant>

int main()
{
  std::variant<int, float, char> var { 42.0F };

  const std::size_t idx = var.index();

  auto res = std::get<idx>(var);

  return 0;
}

ত্রুটি std::getকলটিতে ঘটে :

error: no matching function for call to get<idx>(std::variant<int, float, char>&)’
   auto res = std::get<idx>(var);
                               ^
In file included from /usr/include/c++/8/variant:37,
                 from main.cpp:1:
/usr/include/c++/8/utility:216:5: note: candidate: template<long unsigned int _Int, class _Tp1, class _Tp2> constexpr typename std::tuple_element<_Int, std::pair<_Tp1, _Tp2> >::type& std::get(std::pair<_Tp1, _Tp2>&)’
     get(std::pair<_Tp1, _Tp2>& __in) noexcept
     ^~~
/usr/include/c++/8/utility:216:5: note:   template argument deduction/substitution failed:
main.cpp:9:31: error: the value of idx is not usable in a constant expression
   auto res = std::get<idx>(var);
                               ^
main.cpp:7:15: note: std::size_t idx is not const
   std::size_t idx = var.index();
               ^~~

আমি এটা কিভাবে ঠিক করবো?


3
আমি সন্দেহ করি আপনি যে ত্রুটিটি পাচ্ছেন তা সূচকটির সাথে ধ্রুবক প্রকাশ না হওয়ার সাথে সম্পর্কিত। দয়া করে সংকলক ত্রুটি বার্তাগুলি পোস্ট করুন যাতে আমরা অর্থবহ সহায়তা সরবরাহ করতে পারি।
পাততাহুলিগান

অনুপস্থিত অনুপস্থিত?
Rlyeh

উপস! আপনি একটি ত্রুটি সম্পর্কে কথা বলেছেন, তবে আপনি ত্রুটির সঠিক পাঠ্য পোস্ট করেন নি।
জোনাথন উড

1
বাদ দেওয়ার জন্য দুঃখিত, আমি প্রশ্নটি আপডেট করেছি
অ্যালেক্স

উত্তর:


4

মূলত, আপনি পারবেন না।

তুমি লিখেছিলে:

আমি সেখানে কী জানি না, তবে ধন্যবাদ, বৈকল্পিকটি কী করে

... তবে কেবল রানটাইমে, সংকলন-সময়ে নয়।
এবং এর অর্থ আপনার idxমানটি সংকলন-সময় নয়।
আর যে মানে কি ব্যবহার করতে পারবেন না get<idx>()সরাসরি।

আপনি যা কিছু করতে পারেন তা হল একটি সুইচ স্টেটমেন্ট; কুৎসিত, তবে এটি কার্যকর হবে:

switch(idx) {
case 0: { /* code which knows at compile time that idx is 0 */ } break;
case 1: { /* code which knows at compile time that idx is 1 */ } break;
// etc. etc.
}

এটি বরং কুরুচিপূর্ণ। মতামতগুলির পরামর্শ অনুসারে, std::visit()আপনিও (যা উপরের কোডের থেকে খুব আলাদা নয়, এটি স্পষ্ট হওয়ার পরিবর্তে ভেরিয়ডিক টেম্পলেট আর্গুমেন্টগুলি ব্যবহার না করে) এবং সম্পূর্ণরূপে স্যুইচ এড়াতে পারেন। অন্যান্য সূচক-ভিত্তিক পদ্ধতির জন্য (নির্দিষ্ট নয় std::variant), দেখুন:

রান-টাইম সংখ্যার টেমপ্লেট পরামিতিগুলির অনুকরণের জন্য ইডিয়ম?


@ ক্যালথ: হ্যাঁ সম্পাদনা করা হয়েছে।
einpoklum

5

সংকলকটির কাজ করার idxজন্য সংকলনের সময়টির মানটি জানা দরকার std::get<idx>(), কারণ এটি একটি টেমপ্লেট আর্গুমেন্ট হিসাবে ব্যবহৃত হচ্ছে।

প্রথম বিকল্প: কোডটি যদি সংকলনের সময় চালানো বোঝানো হয়, তবে সবকিছু তৈরি করুন constexpr:

constexpr std::variant<int, float, char> var { 42.0f };

constexpr std::size_t idx = var.index();

constexpr auto res = std::get<idx>(var);

এই কাজ করে কারণ std::variantহয় constexpr(তার কনস্ট্রাকটর ও পদ্ধতি সব বন্ধুত্বপূর্ণ constexpr)।

দ্বিতীয় বিকল্প: কোডটি সংকলনের সময় চালানো না বোঝার জন্য, সম্ভবত resএটির ক্ষেত্রে, সংকলকটি সংকলন করতে গিয়ে টাইপের প্রকারটি হ্রাস করতে পারে না , কারণ এটি তিনটি ভিন্ন জিনিস ( int, floatবা char) হতে পারে । সি ++ একটি স্ট্যাটিক্যালি টাইপযুক্ত ভাষা এবং সংকলকটি অবশ্যই নিম্নলিখিত ধরণের auto res = ...অভিব্যক্তি থেকে ধরণের ধরণটি সক্ষম করতে সক্ষম হবে (অর্থাত এটি সর্বদা একই ধরণের হতে হবে)।

আপনি std::get<T>কোনও সূচকের পরিবর্তে প্রকারের সাথে ব্যবহার করতে পারেন , যদি আপনি ইতিমধ্যে জানেন তবে এটি কী হবে:

std::variant<int, float, char> var { 42.0f }; // chooses float

auto res = std::get<float>(var);

সাধারণভাবে, std::holds_alternativeবর্ণটি প্রদত্ত প্রতিটি প্রকারের ধারণ করে কিনা তা পরীক্ষা করে দেখুন এবং সেগুলি পৃথকভাবে পরিচালনা করুন:

std::variant<int, float, char> var { 42.0f };

if (std::holds_alternative<int>(var)) {
    auto int_res = std::get<int>(var); // int&
    // ...
} else if (std::holds_alternative<float>(var)) {
    auto float_res = std::get<float>(var); // float&
    // ...
} else {
    auto char_res = std::get<char>(var); // char&
    // ...
}

বিকল্পভাবে আপনি ব্যবহার করতে পারেন std::visit। এটি কিছুটা জটিল:

std::variant<int, float, char> var { 42.0f };

std::size_t idx = var.index();

std::visit([](auto&& val) {
    // use val, which may be int&, float& or char&
}, var);

বিশদ ও উদাহরণের জন্য std :: দেখুন ।


3

সমস্যাটি হ'ল std::get<idx>(var);(এর জন্য idx) একটি সংকলন সময় জ্ঞাত মান প্রয়োজন।

সুতরাং একটি constexprমান

// VVVVVVVVV
   constexpr std::size_t idx = var.index();

কিন্তু আরম্ভ করতে idxযেমন constexpr, এছাড়াও varহতে হয়constexpr

// VVVVVVVVV
   constexpr std::variant<int, float, char> var { 42.0F };

… এবং একটি কনটেক্সটপ্রিয়া ভেরিয়েন্ট খুব বৈকল্পিক নয়।
ডেভিস হেরিং

@ ডেভিস হেরিং - এটিও সত্য।
সর্বোচ্চ 66

2

সমস্যাটি টেমপ্লেটগুলি সংকলন সময়ে ইনস্ট্যান্ট করা থেকে উদ্ভূত হয় যখন আপনি সূচকটি রান-টাইমে গণনা করা হয়। একইভাবে, সি ++ প্রকারগুলি সংকলন-সময়ে সংজ্ঞায়িত করা হয় সুতরাং এমনকি autoঘোষণার সাথে resপ্রোগ্রামটি সু-গঠনের জন্য অবশ্যই একটি কংক্রিট টাইপ থাকতে হবে। এর অর্থ হ'ল টেমপ্লেটের কোনও সীমাবদ্ধতা ছাড়াই আপনি যা করার চেষ্টা করছেন তা অ-ধ্রুবক প্রকাশের পক্ষে সহজাত অসম্ভব std::variant। কিভাবে এই চারপাশে কাজ করবে?

প্রথমত, যদি আপনার বৈকল্পিক সত্যই একটি ধ্রুবক অভিব্যক্তি হয়, কোডটি সংকলন করে এবং প্রত্যাশার মতো কাজ করে

#include <variant>

int main()
{
  constexpr std::variant<int, float, char> var { 42.0f };

  constexpr std::size_t idx = var.index();

  auto res = std::get<idx>(var);

  return 0;
}

অন্যথায় আপনাকে কিছু ম্যানুয়াল ব্রাঞ্চিং প্রক্রিয়া ব্যবহার করতে হবে

if (idx == 0) {
    // Now 'auto' will have a concrete type which I've explicitly used
    int value == std::get<0>(var);
}

আপনি এই শাখাগুলি দর্শনার্থীর প্যাটার্নটি ব্যবহার করে সংজ্ঞায়িত করতে পারেন, স্ট্যান্ড :: দেখুন দেখুন ।


1

সি ++ এর মডেলটিতে এটি সহজাত অসম্ভব; বিবেচনা

template<class T> void f(T);
void g(std::variant<int,double> v) {
  auto x=std::get<v.index()>(v);
  f(x);
}

যা fবলা হচ্ছে, f<int>বা f<double>? যদি এটি "উভয়" হয়, তার অর্থ gএকটি শাখা রয়েছে (যা এটি না) বা এর দুটি সংস্করণ রয়েছে g(যা সমস্যাটিকে কেবল তার কলারের দিকে ঠেলে দেয়)। এবং f(T,U,V,W)কোথাও চিন্তা করুন কম্পাইলারটি কোথায় থামবে?

আসলে সি ++ এর জন্য একটি জেআইটির জন্য একটি প্রস্তাব রয়েছে যা fযখন ডাকা হয় তখন তাদের অতিরিক্ত সংস্করণগুলি সংকলন করে এই জাতীয় জিনিসগুলিকে অনুমতি দেয় তবে এটি খুব তাড়াতাড়ি।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.