GCC 中模板化转换运算符中的错误:解决方法?

Hen*_*enk 5 c++ gcc sfinae implicit-conversion

我想要一个代表具有某种维度的单位的类。这应该表示 1.5m^2 之类的东西。应允许与某种类型进行标量乘法,并且无量纲单位的行为应与基础类型完全相同。这是我的解决方案:

#include <type_traits>

template<typename T, int Dim>
class Unit {
    public:
    explicit Unit(T t): _value(t) {}

    template<int D = Dim, typename std::enable_if_t<D==0, int> = 0>
    operator T() { static_assert(Dim==0, ""); return _value; } //static_assert not necessary, but gives error if template is removed
    T _value;
};

template<typename S, typename T, int Dim>
auto operator*(S s, Unit<T,Dim> unit)
{
    return Unit<T, Dim>(s * unit._value);
}

auto main() -> int
{
    auto i = double{0};

//Scalar test
    auto scalar = int{0};
    auto x = Unit<double,1>(i);
    auto test = scalar * x;

//Conversion test
    auto y = Unit<double,0>(i);
    return y + i;
}
Run Code Online (Sandbox Code Playgroud)

这在 clang 中工作得很好(https://godbolt.org/z/8Pev7W6Y1)。但是,由于模板化转换运算符(转换运算符:gcc vs clang)的 GCC 错误,这在 GCC 中不起作用。

不可能删除 SFINAE 结构,因为它(正确地)遇到了static_assert.

您是否有在 GCC 中也能运行的等效代码的想法?该代码应该可以在 C++17 中使用两种编译器运行。

for*_*818 4

您可以使用专业化代替 SFINAE。为了避免太多重复,您可以将公共部分(任何不依赖于 的部分Dim)移至基类:

#include <type_traits>

template <typename T>
class base_unit {
    public:
    explicit base_unit(T t): _value(t) {}
    T _value;
};


template<typename T, int Dim>
class Unit : public base_unit<T> {
public:
    explicit Unit(T t): base_unit<T>(t) {}
};

template <typename T>
class Unit<T,0> : public base_unit<T> {
public:
    explicit Unit(T t) : base_unit<T>(t) {}
    operator T() { return base_unit<T>::_value; }
};

template<typename S, typename T, int Dim>
auto operator*(S s, Unit<T,Dim> unit)
{
    return Unit<T, Dim>(s * unit._value);
}

auto main() -> int
{
    auto i = double{0};

//Scalar test
    auto scalar = int{0};
    auto x = Unit<double,1>(i);
    auto test = scalar * x;

//Conversion test
    auto y = Unit<double,0>(i);
    return y + i;
}
Run Code Online (Sandbox Code Playgroud)

现场演示

请注意,这有点过时,并且没有考虑更现代的 C++20 方法(例如operator T() requires (Dim == 0)评论中提到的方法)。