仅当没有其他转换可用时如何启用构造函数模板?

How to enable a constructor template only if no other conversion is available?

代码如下

#include <iostream>
#include <type_traits>

template <typename T>
struct bar {
    bar(const bar<T>&) {
        std::cout << "copy ctor\n";
    }

    template <typename U,
        typename = std::enable_if_t<!std::is_convertible_v<U, bar<T>>>>
    bar(U&&) {
        std::cout << "ctor template\n";
    }
};

struct foo {
    operator bar<int>() const {
        return bar<int>( 1 );
    }
    operator int() const {
        return 2;
    }
};

int main() {
    foo my_foo;

    std::cout << "constructor: ";
    bar<int> my_bar( my_foo );

    std::cout << "static_cast: ";
    my_bar = static_cast<bar<int>>(my_foo);
}

produces

constructor: ctor template
static_cast: ctor template

作为输出。

但是我希望 bar 的构造函数模板,即 template <typename U> bar::bar(U&&),仅在 U 尚未转换为 bar<T> 时才启用。在 foo 的情况下,foo::operator bar<int>() const 已经给出了这样的转换。假设我是 bar 的作者并且不了解(或影响)foo 或可能的类似 类。我怎样才能说服编译器在那种情况下使用转换运算符而不完全删除 bar 的 ctor 模板?

哦,看来已经是我想要的样子了。我只需要添加更多打印语句即可看到它:

#include <iostream>
#include <type_traits>

template <typename T>
struct bar {
    bar(const bar<T>&) {
        std::cout << "copy ctor\n";
    }
    template <typename U = T,
        typename = std::enable_if_t<!std::is_convertible_v<U, bar<T>>>>
    bar(U&& val) {
        std::cout << "ctor template: " << val << "\n";
    }
};

struct foo {
    operator bar<int>() const {
        std::cout << "operator bar<int>() -> ";
        return bar<int>( 1 );
    }
    operator int() const {
        std::cout << "operator int() -> ";
        return 2;
    }
};

int main() {
    foo my_foo;

    std::cout << "constructor: ";
    bar<int> my_opt( my_foo );

    std::cout << "static_cast: ";
    my_opt = static_cast<bar<int>>(my_foo);
}

outputs

constructor: operator optional<int>() -> ctor template: 1
static_cast: operator optional<int>() -> ctor template: 1

由于 return 值优化,复制构造函数不会出现在输出中。

编辑:正如 Barry 在评论中指出的那样,这只是偶然起作用,并且可以