检测运算符是否存在并在c ++中可调用(考虑static_asserts)

Ria*_*iaD 6 c++ sfinae template-meta-programming c++17

鉴于2种类型TU我要检测它是否可以调用operator *这些对象之间(即是有可能写t * u在那里t的类型是Tu是类型U)

我正在使用c ++检测习惯用法,但由于它在我的编译器中尚未提供,因此我自己就像这样实现它

struct nonesuch {
    nonesuch() = delete;
    ~nonesuch() = delete;
    nonesuch(nonesuch const&) = delete;
    void operator=(nonesuch const&) = delete;
};

namespace detail {
template <class Default, class AlwaysVoid, template<class...> class Op, class... Args>
struct detector {
    using value_t = std::false_type;
    using type = Default;
};

template <class Default, template<class...> class Op, class... Args>
struct detector<Default, std::void_t<Op<Args...>>, Op, Args...> {
    using value_t = std::true_type;
    using type = Op<Args...>;
};

} // namespace detail

template <template<class...> class Op, class... Args>
using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t;

template< template<class...> class Op, class... Args >
constexpr bool is_detected_v = is_detected<Op, Args...>::value;
Run Code Online (Sandbox Code Playgroud)

现在我有这样的帮手:

template <typename T, typename U>
using multiply = decltype(std::declval<T>() * std::declval<U>());
Run Code Online (Sandbox Code Playgroud)

并检测我是否可以调用它

bool can_multiply = is_detected_v<multiply, T, U>
Run Code Online (Sandbox Code Playgroud)

它几乎没问题,例如按预期打印1,0

std::cout << is_detected_v<multiply, int, int> << std::endl;
std::cout << is_detected_v<multiply, std::vector<int>, std::vector<int>> << std::endl;
Run Code Online (Sandbox Code Playgroud)

但现在我上课了

template<typename T>
class A {
};

template<typename T>
A<T> operator*(const A<T>&, const A<T>&) {
    static_assert(!std::is_same<bool, T>::value);
    return A<T>();
}
Run Code Online (Sandbox Code Playgroud)

这里A<bool>不能乘以,A<bool>但我的代码检测到它是可能的

std::cout << is_detected_v<multiply, A<bool>, A<bool>> << std::endl; // 1
A<bool>() * A<bool>(); // does't compile
Run Code Online (Sandbox Code Playgroud)

所以,我的问题是,如何修复我的代码,以便在static_asserted出来时不检测方法?我想我可以替换static_assert一些sfinae但我不想(因为我没有访问权限,除了static_asserts有更好的错误消息).

Bar*_*rry 7

所以,我的问题是,如何修复我的代码,以便在static_asserted出来时不检测方法?

你根本做不到.这只是其中一个缺点static_assert- 无法从外部验证操作的有效性.这是因为static_assert在实例化的"直接上下文"中没有发生operator*,因此SFINAE不适用 - 它将永远是一个硬错误.

我想我可以用一些sfinae替换static_assert但我不想(因为我没有访问权限,除了static_asserts有更好的错误消息).

我同情.但这基本上是权衡取舍.SFINAE和类型检查,或static_assert更明确的错误.(当然在这种情况下你可以写一个非模板,A<bool> operator*(A<bool> const&, A<bool> const&)但这可能除了这一点).