1. 程式人生 > >C++:error C2228: left of '.str' must have class/struct/union

C++:error C2228: left of '.str' must have class/struct/union

如下程式碼報error C2228: left of '.str' must have class/struct/union

#include <string>
#include <iostream>
#include <vector>

using namespace std;

template <typename T>
class ValueBox {
private:
    T value;

private:

    template<typename U, 
        typename std::enable_if<std::is_class<U>::value && !std::is_same<U, string>::value, U>::type* = nullptr, 
        typename std::enable_if<!class_str<U>::ret, U>::type* = nullptr>
    std::string str(const T&) {
        cout << "1.---------------------" << endl;
        return "null";
    };

    template<typename U, 
        typename std::enable_if<std::is_class<U>::value && std::is_same<U, string>::value, U>::type* = nullptr>
    std::string str(const T&) {
        cout << "2.---------------------" << endl;
        return value;
    };

    template<typename U, 
        typename std::enable_if<std::is_class<U>::value && !std::is_same<U, string>::value, U>::type* = nullptr, 
        typename std::enable_if<class_str<U>::ret, U>::type* = nullptr>
    std::string str(const T&) {
        cout << "3.---------------------" << endl;
        return value.str();
    };

    template<typename U, 
        typename std::enable_if<!std::is_class<U>::value && std::is_arithmetic<U>::value, U>::type* = nullptr>
    std::string str(const T&) {
        cout << "4.---------------------" << endl;
        return std::to_string(value);
    };

public:
    ValueBox(const T& _value) : value(_value) {
    }

    const T& getValue() const {
        return value;
    };

    T& getValue() {
        return value;
    };

    std::string str() {
        return str<T>(value);
    };
};


int main() {
    ValueBox<string> s("sddds");
    cout << s.str() << endl;

    ValueBox<bool> j ( true);
    cout << j.str() << endl;

    ValueBox<int> i(100);
    cout << i.str() << endl;

    ValueBox<float> f ( 10.6f);
    cout << f.str() << endl;

    ValueBox<Box> b1 (Box());
    cout << b1.str() << endl;

    ValueBox<Bin> b2 (Bin());
    cout << b2.str() << endl;

    return 1;
}

報錯的原因是C++ 編譯器把ValueBox<Box> b1 (Box());中的b1看成的函式定義,把Box()看成是返回值為Box的無引數函式,只不過此時的引數名稱未定義罷了。這種錯誤有一個通用的名稱,叫做:Most Vexing Parse

修改的方法有如下幾種:

1、將Box單獨放一行並初始化
Box b;   // 不能使用Box b();,這樣b又會被當成函式定義了
ValueBox<Box> b1 (b);

2、將Box()用括號包起來,這樣Box()就不會被看成是函數了
ValueBox<Box> b1 ((Box()));

3、使用C++1中的統一初始化語法,即使用{}
ValueBox<Box> b1 {Box()};

 

參考文件
C++語法分析中最讓人頭疼的歧義
Item 6. Be alert for C++'s most vexing parse
Effective STL 筆記: Item 6--Be alert for C++'s most vexing parse