【问题标题】:Why does clang++ warn about inlined enable_if and then fail to link?为什么 clang++ 会警告内联 enable_if 然后无法链接?
【发布时间】:2015-01-16 07:22:57
【问题描述】:

我正在玩弄一个想法,但遇到了一个让我非常摸不着头脑的问题。在我开始将这个想法迁移到更大的框架之前,我希望有人能给我一个清晰的(最好是引用的)解释。

我正在运行以下实验:

/*
 * gcc -Wall -O0 -g -std=c++11 main.cc -lstdc++ -lm -o mathras
 * clang++ -Wall -O0 -g -std=c++11 main.cc -lstdc++ -lm -o mathras
 */

#include <type_traits>
#include <functional>

template<typename U, typename V>
struct is_comparable {
    static constexpr bool value = (std::is_integral<U>::value && std::is_integral<V>::value) || (std::is_floating_point<U>::value && std::is_floating_point<V>::value);
};


template<typename T>
class interval {
    public:
        inline interval();
        inline interval(const T& x);
        inline interval(const T& min, const T& max);
    public:
        template<typename U>
        constexpr typename std::enable_if<!is_comparable<T, U>::value, bool>::type
            operator==(const interval<U>&) const noexcept;
        template<typename U>
        inline typename std::enable_if<is_comparable<T, U>::value, bool>::type
            operator==(const interval<U>&) const noexcept;
        inline bool operator!=(const T& rhs) const noexcept;
        template<typename U>
        constexpr typename std::enable_if<!is_comparable<T, U>::value, bool>::type
            operator!=(const interval<U>&) const noexcept;
        template<typename U>
        inline typename std::enable_if<is_comparable<T, U>::value, bool>::type
            operator!=(const interval<U>& rhs) const noexcept;
    public:
        inline T& max() noexcept;
        inline T const& max() const noexcept;
        inline T& min() noexcept;
        inline T const& min() const noexcept;
    protected:
        T min_;
        T max_;
};

#include <iostream>
#include <iomanip>
using namespace std;

int main(int argc, char** argv) {
    interval<int> a(0, 25);
    interval<unsigned> b(0, 25);
    interval<float> c(0, 25);
    interval<double> d(0, 25);
    cout << boolalpha <<
            "a == b = " << (a == b) << endl <<
            "a != b = " << (a != b) << endl <<
            "a == c = " << (a == c) << endl <<
            "a != c = " << (a != c) << endl <<
            "a == d = " << (a == d) << endl <<
            "a != d = " << (a != d) << endl <<
            "b == c = " << (b == c) << endl <<
            "b != c = " << (b != c) << endl <<
            "b == d = " << (b == d) << endl <<
            "b != d = " << (b != d) << endl <<
            "c == d = " << (c == d) << endl <<
            "c != d = " << (c != d) << endl <<
        flush;
    return 0;
};


template<typename T>
inline interval<T>::interval():
    min_(),
    max_()
{ };

template<typename T>
inline interval<T>::interval(const T& x):
    interval(x, x)
{ };

template<typename T>
inline interval<T>::interval(const T& min, const T& max):
    min_((max < min) ? max : min),
    max_((min > max) ? min : max)
{ };

template<typename T>
inline T& interval<T>::max() noexcept {
    return this->max_;
};

template<typename T>
inline T const& interval<T>::max() const noexcept {
    return this->max_;
};

template<typename T>
inline T& interval<T>::min() noexcept {
};

template<typename T>
inline T const& interval<T>::min() const noexcept {
    return this->min_;
};

template<typename T>
template<typename U>
constexpr typename std::enable_if<!is_comparable<T, U>::value, bool>::type
interval<T>::operator==(const interval<U>&) const noexcept {
    return false;
};

template<typename T>
template<typename U>
inline typename std::enable_if<is_comparable<T, U>::value, bool>::type
interval<T>::operator==(const interval<U>& rhs) const noexcept {
    return (this->min_ == rhs.min()) && (this->max_ == rhs.max());
};

template<typename T>
template<typename U>
constexpr typename std::enable_if<!is_comparable<T, U>::value, bool>::type
interval<T>::operator!=(const interval<U>&) const noexcept {
    return true;
};

template<typename T>
template<typename U>
inline typename std::enable_if<is_comparable<T, U>::value, bool>::type
interval<T>::operator!=(const interval<U>& rhs) const noexcept {
    return (this->min_ != rhs.min()) || (this->max_ != rhs.max());
};

如您所见,这看起来很简单。 is_comparable 确定一个区间的两个数字是否可比较,然后类区间通过 enable_if 使用它来专门比较。

gcc 和 vc++(根据http://webcompiler.cloudapp.net/)都没有抱怨。它们都警告(适当且符合预期的)无符号与有符号比较,但继续编译、链接并产生预期的输出。

这就是让我摸不着头脑的原因。 Clang 不会抱怨签名。相反,它会产生以下警告...

main.cc:24:4: warning: inline function 'interval<int>::operator==<float>' is not defined [-Wundefined-inline]
                        operator==(const interval<U>&) const noexcept;
                        ^
main.cc:57:22: note: used here
                        "a == c = " << (a == c) << endl <<
                                          ^
main.cc:31:4: warning: inline function 'interval<int>::operator!=<float>' is not defined [-Wundefined-inline]
                        operator!=(const interval<U>&) const noexcept;
                        ^
main.cc:58:22: note: used here
                        "a != c = " << (a != c) << endl <<
                                          ^
main.cc:24:4: warning: inline function 'interval<int>::operator==<double>' is not defined [-Wundefined-inline]
                        operator==(const interval<U>&) const noexcept;
                        ^
main.cc:59:22: note: used here
                        "a == d = " << (a == d) << endl <<
                                          ^
main.cc:31:4: warning: inline function 'interval<int>::operator!=<double>' is not defined [-Wundefined-inline]
                        operator!=(const interval<U>&) const noexcept;
                        ^
main.cc:60:22: note: used here
                        "a != d = " << (a != d) << endl <<
                                          ^
main.cc:24:4: warning: inline function 'interval<unsigned int>::operator==<float>' is not defined [-Wundefined-inline]
                        operator==(const interval<U>&) const noexcept;
                        ^
main.cc:61:22: note: used here
                        "b == c = " << (b == c) << endl <<
                                          ^
main.cc:31:4: warning: inline function 'interval<unsigned int>::operator!=<float>' is not defined [-Wundefined-inline]
                        operator!=(const interval<U>&) const noexcept;
                        ^
main.cc:62:22: note: used here
                        "b != c = " << (b != c) << endl <<
                                          ^
main.cc:24:4: warning: inline function 'interval<unsigned int>::operator==<double>' is not defined [-Wundefined-inline]
                        operator==(const interval<U>&) const noexcept;
                        ^
main.cc:63:22: note: used here
                        "b == d = " << (b == d) << endl <<
                                          ^
main.cc:31:4: warning: inline function 'interval<unsigned int>::operator!=<double>' is not defined [-Wundefined-inline]
                        operator!=(const interval<U>&) const noexcept;
                        ^
main.cc:64:22: note: used here
                        "b != d = " << (b != d) << endl <<
                                          ^

根据警告,它似乎并没有抱怨与interval&lt;U&gt; 有任何关系,而是抱怨U 本身,除非这只是它的警告输出中的一个怪癖。

无论如何,它都会编译,但在链接时,未定义的引用会出错,但它一开始就内联失败了。

我用 clang 3.3 和 3.4 尝试过,结果相同。

第一个问题。为什么?我的代码对我来说看起来不错(忽略签名等预期内容)。我实际上是在某个地方犯了一个重大的错误,而 Clang 正在接受(而他们其他编译器实际上是错误的),还是 clang 只是对此有错误?

第二个问题。不管为什么,完成这项任务的最适合交叉编译器的方法是什么?

【问题讨论】:

  • 这与this 问题有点像,尽管无论出于何种原因,gcc 似乎无论如何都在实例化模板,我的直觉是clang 是正确的,模板定义必须在模板所在的位置可见用来。您也可以在main 下方显式实例化所需的模板,但确保定义在使用之前出现当然更好。
  • @user657267 这就是我得出的结论(请参阅我自己的答案)。越用clang越喜欢它,但要摆脱gcc给我的多年习惯需要时间。

标签: c++ c++11 clang enable-if


【解决方案1】:

愚弄我。花了最后一个小时+一无所获。

我使用 gcc waaaay 太久了(最近才切换到 clang)。

警告告诉我它没有被定义,因为它没有被定义。它们在下面定义main()。似乎 gcc/vc++ 进行了预扫描,因此即使严格来说它们不应该被定义。

我刚刚将 main() 移到了底部,瞧。

我想我只需要使用 stackoverflow 作为一个共鸣板来解决我自己的问题。

【讨论】:

    猜你喜欢
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 2021-10-23
    • 1970-01-01
    • 2015-06-21
    • 1970-01-01
    • 2023-01-09
    • 2017-12-21
    相关资源
    最近更新 更多