在Visual Studio 10中使用类型转换操作符重载时出现C2440错误

时间:2016-02-16 17:27:19

标签: c++ templates visual-c++ visual-c++-2010

我遇到了C2440错误:

C:\code>cl test.cpp /EHsc                       

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86                 
Copyright (C) Microsoft Corporation.  All rights reserved.                                      

test.cpp                                                                                        
test.cpp(18) : error C2440: 'initializing' : cannot convert from 'D<TYPE,SELECTOR>' to 'int'
    with
    [
        TYPE=int,
        SELECTOR=int
    ]
    Ambiguous user-defined-conversion

当我尝试使用visual studio 10编译以下测试代码时,它似乎与clang -Weverything和armcc一起正常工作。

是否有一个特殊的原因导致这种情况无效,除了“不要那样做”之外还有其他解决办法吗?

#include <iostream>

template <typename TYPE, typename SELECTOR = int> struct D  {
    TYPE x;
    D() : x(2) {}
    D(TYPE X) : x(X) {}

    operator const TYPE&() const { return x; }
};
template <typename TYPE> struct D<TYPE, int> : public D<TYPE, char> {
    D() : D<TYPE, char>(3) {}
    operator TYPE&() { return D<TYPE, char>::x; }
};

int main() {

    D<int, int> test3;
    int t3 = test3;

    D<int, char> test2;
    int t2 = test2;

    std::cout << +t3 << " " << +t2 << "\n";  // Expected output "3 2" (which we get from clang)
    return 0;
}
编辑:我知道D<TYPE, int>案例提供左值,而D<TYPE, non-int>案例只提供右值。这是非常有意的。

2 个答案:

答案 0 :(得分:1)

operator TYPE&()有两个功能:

public D<int, int>::operator int&() 
private D<int, char>::operator const int&() const

可以明确地称之为:

int t3 = test3.::D<int, int>::operator int&();

关于gcc允许调用(如果是puplic继承):

int t3 = test3.::D<int, char>::operator const int&();

但对于msvc isn&#t; t

gcc允许两种变体,似乎是对的:

D<int, int> test3;
const D<int, int> test4;

int t3 = test3; // called D<int, int>::operator int&();
int t4 = test4; // called D<int, char>::operator const int&() const;

msvc仅允许第二种变体。

msvc不认为test3不是const,也不选择const和非const函数。

似乎是msvc bug。

答案 1 :(得分:1)

Ambiguous user-defined-conversion

关键字含糊不清。

D<int, int> test3;
int t3 = test3;

这里编译器不知道使用const int &D<int, char>::operator const int &()还是int &D<int, int>::operator int &()

问题是t3int而不是int&const int&。 如果您实际使用引用,一切正常(或至少按预期):

D<int, int> test3;
int& t31 = test3; //OK
const int& t32 = test3; //OK

D<int, char> test2;
int& t21 = test2; //Doesn't work
const int& t22 = test2; //OK

问题是编译器决定使用基类的const版本还是继承类的非const版本。

我建议你在继承类中重载操作符的const版本,这样编译器就可以选择只在这个类中使用哪一个:

#include <iostream>

template <typename TYPE, typename SELECTOR = int> struct D {
    TYPE x;
    D() : x(2) {}
    D(TYPE X) : x(X) {}

    operator const TYPE&() const { return x; }
};
template <typename TYPE> struct D<TYPE, int> : public D<TYPE, char> {
    D() : D<TYPE, char>(3) {}

    operator const TYPE&() const { return D<TYPE, char>::x; }
    operator TYPE&() { return D<TYPE, char>::x; }
};

int main() {

    D<int, int> test3;
    int t3 = test3; //OK
    int& t31 = test3; //OK
    const int& t32 = test3; //OK

    D<int, char> test2;
    int t2 = test2; //OK
    //int& t21 = test2; //Doesn't work
    const int& t22 = test2; //OK

    std::cout << +t3 << " " << +t2 << "\n";  // Expected output "3 2" (which we get from clang)
    return 0;
}

解决此问题的其他方法:

您现在可以手动转换为int&

D<int, int> test3;
int t3 = (int&)test3;

或手动转换为const int&

D<int, int> test3;
int t3 = (const int&)test3;

或明确调用函数

D<int, int> test3;
int t3 = test3.operator int &();

D<int, int> test3;
int t3 = test3.operator const int &();

或者您可以同时使用const

template <typename TYPE> struct D<TYPE, int> : public D<TYPE, char> {
    D() : D<TYPE, char>(3) {}
    operator const TYPE&() const { return D<TYPE, char>::x; }
};

或者你可以删除函数的重定义(因为TYPE不会改变)。

template <typename TYPE, typename SELECTOR = int> struct D {
    TYPE x;
    D() : x(2) {}
    D(TYPE X) : x(X) {}

    operator const TYPE&() const { return x; }
};

template <typename TYPE> struct D<TYPE, int> : public D<TYPE, char> {
    D() : D<TYPE, char>(3) {}
};

然而,我猜后两种变体并不是你想要的const