4

Let us consider the following examples of where implicit type conversion works and where it doesn't:

#include <iostream>
#include <vector>

struct Thingy
{
    void write()
    {
        std::cout << "x" << std::endl;
    }
};

struct Node
{
    Thingy a;
    int data;
    operator Thingy&(){return a;}
};

void f(Thingy thingy)
{
    thingy.write();
}

template <typename TIterator>
void f (TIterator begin, TIterator end)
{
    for (TIterator it = begin; it != end; ++it)
        it->write();
}

int main()
{
    std::vector<Node> vector(10);

    f(vector.begin(), vector.end());  // Doesn't compile
    f(vector[3]);                     // compiles
    vector[3].write();                // Doesn't compile
    return 0;
}

Why is this so? The

void Node::write(); 

Should not be fundamentally different from:

void write(Node* this);

Is there any way to make my example code compile and run?

EDIT:

I understand the mechanics of why it doesn't work, I want to understand the philosophy. Why did the C++ Standard committee think it was a bad Idea?

3
  • 4
    Neither of those compile because Node doesn't have a write function. Commented Aug 11, 2013 at 14:09
  • And It should not have one. I have an algorithm that works on a range of Thingies. I have a range of Nodes. How can I make it work? Commented Aug 11, 2013 at 14:21
  • 1
    See the "wrap iterator" solution in my post. Or you can simply add the write method inside Node and forward the call to Thingy. Commented Aug 11, 2013 at 15:08

1 Answer 1

2

It doesn't work because you never ask the compiler for a conversion when you are doing:

it->write();

I guess it should work with a static_cast:

static_cast<Thingy&>(*it).write();

But I'm barely sure you should simply use:

it->get_a().write();

Or better, as others said, declare a method write in Node.

The implicit conversions can be evil.

Because you can't change the f function, you should just wrap the iterator so it can dereferences a Thingy instead of a Node, if you can use Boost:

#include <iostream>
#include <vector>
#include <boost/iterator/transform_iterator.hpp>
struct Thingy
{
    void write()
    {
        std::cout << "x" << std::endl;
    }
};

struct Node
{
    Thingy a;
    int data;
    operator Thingy&(){return a;}
};

void f(Thingy thingy)
{
    thingy.write();
}

template <typename TIterator>
void f (TIterator begin, TIterator end)
{
    for (TIterator it = begin; it != end; ++it)
        it->write();
}

struct Node2Thingy
{
  typedef Thingy& result_type;
  Thingy& operator()(Node& n) const { return n.a; }
};

int main()
{
    std::vector<Node> vector(10);

    f(boost::make_transform_iterator(vector.begin(), Node2Thingy()),
         boost::make_transform_iterator(vector.end(), Node2Thingy()));
    f(vector[3]);                     // compiles


    return 0;
}

Work on g++ 4.8.1 (but surely on older version too).

You tried to resolve your problem by adding an "implicit" indirection, but in that case, it can't work. You can resolve it by adding an explicit indirection.

To answer your question, there is no philosophy behind the scene. It's purely mechanic, the C++ use types that are resolved at compilation time so everything have its type before the execution time. How would you want that the compiler guess that the conversion operator must be called on Node.

Sign up to request clarification or add additional context in comments.

6 Comments

Thank you, but I cannot make changes to the body of f function.
I tried your code and I get: /usr/include/boost/utility/result_of.hpp:82: error: no class template named 'result' in 'struct Node2Thingy'
I can't understand the documentation. They say: "f(*i) must be valid where f is an object of type UnaryFunction, i is an object of type Iterator, and where the type of f(*i) must be result_of<UnaryFunction(iterator_traits<Iterator>::reference)>::type." Could you help me understand this?
try to add typedef Thingy& result; inside the Node2Thingy struct as shown in my edited response.
I get "/usr/include/boost/utility/result_of.hpp:82: error: 'typename Node2Thingy::result' names 'Node2Thingy::result', which is not a class template". Does it work on your computer?
|

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.