2

I am parsing a text based file to read variables from it. Existence of variables in the file is important, so I decided to write a template class which will hold both value of the variable (Value) and its existence flag (Exists).

template<class Type>
class MyVariable
{
    public:
        Type    Value;
        bool    Exists;
        MyVariable()
            : Exists(false), Value(Type())
        {
        }
        MyVariable(const Type & Value)
            : Exists(true), Value(Value)
        {
        }
        MyVariable(const Type && Value)
            : Exists(true), Value(std::move(Value))
        {
        }
        MyVariable(const Type & Value, bool Existance)
            : Exists(Existance), Value(Value)
        {
        }
        MyVariable(const Type && Value, bool Existance)
            : Exists(Existance), Value(std::move(Value))
        {
        }
        size_t size() const
        {
            return Value.size();
        }
        const MyVariable & operator=(const MyVariable &  Another)
        {
            Value   = Another.Value;
            Exists  = true;
        }
        const MyVariable & operator=(const MyVariable && Another)
        {
            Value   = std::move(Another.Value);
            Exists  = true;
        }
        const Type & operator[](size_t Index) const
        {
            return Value[Index];
        }
              Type & operator[](size_t Index)
        {
            return Value[Index];
        }
        operator const Type & () const
        {
            Value;
        }
        operator Type &()
        {
            Value;
        }
};

The stored variable type will occasionally be std::vector, so I overloaded the subscript operator operator[] to directly access the elements of the vector. So that I can make the Value and Exists members private.

I use this class like this in the code:

const MyVariable<std::vector<int>> AVector({11, 22, 33, 44 ,55});
for (size_t i=0; i<AVector.size(); i++)
{
    std::wcout << L"Vector element #" << i << L" --> " << AVector.Value[i]  << std::endl;   // Works okay.
    std::wcout << L"Vector element #" << i << L" --> " << AVector[i]        << std::endl;   // Gives error.
}

I get the following error message:

Error C2679 binary '<<': no operator found which takes a right-hand operand of type 'const std::vector<int,std::allocator<_Ty>>' (or there is no acceptable conversion)

What am I doing wrong here?

1
  • You may look at optional (which doesn't require that Type is default constructible). Commented Dec 1, 2015 at 9:23

4 Answers 4

4
const Type & operator[](size_t Index) const
{
    return Value[Index];
}

Type & operator[](size_t Index)
{
    return Value[Index];
}

Those return types are wrong; you are returning the contained type, not the container type. You can use decltype for this:

auto operator[](size_t Index) const -> decltype(Value[Index]) 
{
    return Value[Index];
}

auto operator[](size_t Index) -> decltype(Value[Index]) 
{
    return Value[Index];
}
Sign up to request clarification or add additional context in comments.

2 Comments

This works. Thank you. Should I change decltype(Value[Index]) to const decltype(Value[Index]) & and decltype(Value[Index]) & respectively?
@hkBattousai Nah, the decltypes will work just as you want in this case.
3

You're returning wrong type.

For const Type & operator[](size_t Index) const, Type is std::vector<int>, which means you're trying to return a vector, not the element of the vector.

Try to change the type of return value to typename Type::value_type, such as

const typename Type::value_type& operator[](size_t Index) const

Comments

2

Your operator overload is declared

const Type & operator[](size_t Index) const

But AVector is declared as

const MyVariable<std::vector<int>>

So Type in your case is std::vector, and there is no << operator overload that accepts a std::vector for cout.

Comments

0

TartanLlama's and songyuanyao's answers are correct only when the contained variable type (i.e.; ValueType) is std::vector. If we attempt to store a fundamental data type (e.g.; int or float), the compiler (MSVC14) gives the error below since there won't be any implicit subscript operator operator[] or value_type member type definition inside.

'InputFileVariable<bool,std::string>::value_type': is not a type name, static, or enumerator  
'InputFileVariable<int,std::string>::value_type': is not a type name, static, or enumerator  
'InputFileVariable<uintmax_t,std::string>::value_type': is not a type name, static, or enumerator  
'InputFileVariable<float,std::string>::value_type': is not a type name, static, or enumerator

I found the solution by using function templates. I rewrote the subscript operators as templates, so that the compiler doesn't create the subscript member functions unless they are called. And since I call them only when the stored element is an std::vector, it doesn't cause any problem with fundamental types.

My working final code is below.

#include <vector>
#include <string>

template<class ValueType, class KeyType = std::string>
class InputFileVariable
{
    public:
        const KeyType   Key;
        ValueType       Value;
        bool            Exists;
        InputFileVariable(KeyType && Key, ValueType && Value, bool Existance = false)
            :   Key     (std::forward<KeyType>  (Key)),
                Value   (std::forward<ValueType>(Value)),
                Exists  (Existance)
        {
        }
        size_t size() const
        {
            return Value.size();
        }
        const InputFileVariable & operator=(InputFileVariable && Another)
        {
            Key     = std::forward<InputFileVariable>(Another).Key;
            Value   = std::forward<InputFileVariable>(Another).Value;
            Exists  = true;
            return *this;
        }
        template <class ElementType = ValueType::value_type>
        const typename ElementType & operator[](size_t Index) const
        {
            return Value[Index];
        }
        template <class ElementType = ValueType::value_type>
        typename ElementType & operator[](size_t Index)
        {
            return Value[Index];
        }
        operator const ValueType & () const
        {
            return Value;
        }
        operator ValueType & ()
        {
            return Value;
        }
};

int wmain(int argc, wchar_t *argv[], wchar_t *envp[])
{
    // Used with "std::vector":
    InputFileVariable<std::vector<int>> MyVar1("MV1", {2, 4, 6, 8}, true);
    const size_t SIZE = MyVar1.size();
    std::cout << "Size = " << SIZE << std::endl;
    int Temp = MyVar1[1];
    MyVar1[1] = MyVar1[2];  // Here we call both the const and non-const operators.
    MyVar1[2] = Temp;
    for (size_t i=0; i<SIZE; i++)
    {
        std::cout << "MyVar1[" << i << "] = " << MyVar1[i] << std::endl;
    }

    // Used with "double":
    InputFileVariable<double> MyVar2("MV2", 3.14, true);
    std::cout << std::endl << "MyVar2    = " << MyVar2 << std::endl;

    std::cout << std::endl;
    _wsystem(L"timeout /t 60 /nobreak");
    return 0;
}

Output:

Size      = 4
MyVar1[0] = 2
MyVar1[1] = 6
MyVar1[2] = 4
MyVar1[3] = 8

MyVar2    = 3.14

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.