开发者

How do I implicitly specialise conversion?

开发者 https://www.devze.com 2023-04-11 02:08 出处:网络
With the following code, if I attempt to convert a template array to std::string, instead of the compiler using the expected std::string conversion method, it raises an ambiguity resolution problem (a

With the following code, if I attempt to convert a template array to std::string, instead of the compiler using the expected std::string conversion method, it raises an ambiguity resolution problem (as it attempts to call the array conversion methods):

#include <iostream>

template<typename TemplateItem>
class TestA
{
    public:
        TemplateItem Array[10];

        operator const TemplateItem *() const {return Array;}
        operator const std::string() const;
};

template<>
TestA<char>::operator const std::string() const
{
    st开发者_StackOverflow中文版d::string Temp("");
    return Temp;
}

int main()
{
    TestA<char> Test2;
    std::string Temp("Empty");
    Temp = Test2; //Ambiguity error. std::string or TemplateItem * ? 
    return 0;
}

What modification do I need to make to the code in order to make it so the code correctly and implicitly resolve to the std::string conversion function? Especially given the const TemplateItem * would be treated as a null-terminated array (which it won't likely be).


First, the reason you have ambiguity: you provide both conversion to char* and conversion to std::string const, and std::string likes them both.

By the way, before getting to your question, the const in operator std::string const was once a good idea, advocated by e.g. Scott Meyers, but is nowadays ungood: it prevents efficient moving.

Anyway, re the question, just avoid implicit conversions. Make those conversions explicit. Now I answered that in response to another SO question, and someone (I believe the person was trolling) commented that C++98 doesn't support explicit type conversion operators. Which was true enough, technically, but pretty stupid as a technical comment. Because you don't need to use the explicit keyword (supported by C++11), and indeed that's not a good way to make the conversions explicit. Instead just name those conversions: use named member functions, not conversion operators.


#include <iostream>

template<typename TemplateItem>
class TestA
{
    public:
        TemplateItem Array[10];

        TemplateItem  const* data() const { return Array; }
        std::string str() const;
};

template<>
std::string TestA<char>::str() const
{
    return "";
}

int main()
{
    TestA<char> test2;
    std::string temp( "Empty" );
    temp = test2.str();     // OK.
    temp = test2.data();    // Also OK.
}

Cheers & hth.


I will add, after thinking about it, here's the reasoning and what should be done:

The operator const TemplateItem *(); Should be deleted.

Why? There never will be an instance where you would want implicit conversion of TestA (or any template class) to a TemplateItem array with an unknown size - because this has absolutely no bounds checking (array could be sizeof 1 or 10 or 1000 or 0) and would likely cause a crash if a calling function or class received the array with no idea what size it is.

If the array is needed, either use the operator[] for direct items, or GetArray (which would signal the user intends to pass an unknown-length array).

Retain operator const std::string. Code will compile. Possible memory issues down the line averted.

(Alf for his efforts has been selected as the 'correct' answer, although this is the more logical option)

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号