C++类模板可以是无意义的专业和实例化的,而无需角度括号?

发布于 2025-02-07 08:22:26 字数 1825 浏览 2 评论 0原文

这实际上是编译和工作的,但这对我来说还不清楚。

#include <iostream>

template <class T>
class LikeA
{
    T m_val{};
    public:
    LikeA() = default;
    explicit LikeA(T iv): m_val(std::move(iv)) {}
    LikeA(LikeA<T> const &) = default;
    LikeA(LikeA<T> &&) noexcept = default;
    ~LikeA() noexcept = default;
    operator T const &() const { return m_val; }
    LikeA<T> &operator=(T nv) { m_val = std::move(nv); return *this; }
    LikeA<T> &operator=(LikeA<T> const &n) { m_val = n.m_val; return *this; }
    LikeA<T> &operator=(LikeA<T> &&n) { m_val = std::move(n.m_val); return *this; }
};

template <class T>
T f (LikeA<T> i)
{
    return i;
}

int main()
{
    std::cout << f(LikeA{3.1415927}) << '\n';  // No template argument? Not a syntax error?
    return 0;
}

我以前是在调用f喜欢f(3.1415927) 之前,我让棉绒检查器说我要让我做一个likea s构造仪explicit。之后,当然,它不能隐式将常数转换为likea。如果您只添加括号(即f({{3.1415927})编译器仍然不知道要选择什么。

在我的完整代码中,实际的模板参数更加详细,所以仅对于笑我来说,将模板名称放在支架初始化器的前面,完全期望

的惊喜,它汇编并ran

我 我只是将我带入了错误的

安全感表面,与参数有关的查找似乎是答案,但是请注意没有角度括号,并且模板没有默认的

参数href =“ https://stackoverflow.com/questions/25742819/function-template-specialization-without-templated-argument”>函数模板专业化而无需模板参数不回答这个问题。

function template gratplate grapplate grapplate grapplate参数关于省略&lt ;&gt;,但这是一个类模板。语法在这里似乎一直都需要角度支架。

This actually compiles and works, but it's unclear to me why.

#include <iostream>

template <class T>
class LikeA
{
    T m_val{};
    public:
    LikeA() = default;
    explicit LikeA(T iv): m_val(std::move(iv)) {}
    LikeA(LikeA<T> const &) = default;
    LikeA(LikeA<T> &&) noexcept = default;
    ~LikeA() noexcept = default;
    operator T const &() const { return m_val; }
    LikeA<T> &operator=(T nv) { m_val = std::move(nv); return *this; }
    LikeA<T> &operator=(LikeA<T> const &n) { m_val = n.m_val; return *this; }
    LikeA<T> &operator=(LikeA<T> &&n) { m_val = std::move(n.m_val); return *this; }
};

template <class T>
T f (LikeA<T> i)
{
    return i;
}

int main()
{
    std::cout << f(LikeA{3.1415927}) << '\n';  // No template argument? Not a syntax error?
    return 0;
}

I was previously calling f like f(3.1415927) before I let a lint checker talk me into making one of LikeAs constructors explicit. After that, of course, it couldn't implicitly convert the constant to a LikeA. If you just add braces (i.e. f({3.1415927}) the compiler still doesn't know what to select.

In my full code the actual template argument is a lot more verbose, so just for grins I put the template name LikeA in front of the brace initializers, fully expecting a syntax error.

To my surprise, it compiled and ran.

Since this was MSVC, at first I though it was just Microsoft lulling me into a sense of false security. But I tested it against several compilers (gcc, clang, zigcc) in Compiler Explorer, and it works on all of them.

How does C++ select the correct template specialization? On the surface, argument-dependent lookup would seem to be the answer, but notice there are no angle brackets, and the template doesn't have a default argument. I definitely remember this being a syntax error at some point in the past.

(Function template specialization without templated argument doesn't answer this because OP actually specifies the arguments).

The cppreference on function template arguments has a quick aside about omitting <> but this is a class template. The syntax here appears to require the angle brackets all the time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

晒暮凉 2025-02-14 08:22:26

由于C ++ 17,编译器可以使用类模板参数扣除(CTAD)自动推导模板的参数类型。如果构造函数能够推断出所有模板参数,则可以显式地跳过模板参数。

因此,您只需

int main()
{
    std::vector v{2, 4, 6, 8};      // same as std::vector<int>
    std::list   l{1., 3., 5.};      // same as std::list<double>
    std::pair   p{false, "hello"};  // same as std::pair<bool, const char *>
    
    std::cout << typeid(v).name() << std::endl;
    std::cout << typeid(l).name() << std::endl;
    std::cout << typeid(p).name() << std::endl;
}

在MSVC下写入以下输出,

class std::vector<int,class std::allocator<int> >
class std::list<double,class std::allocator<double> >
struct std::pair<bool,char const * __ptr64>

请参考 ctad for更多细节。

Since C++17, compiler can automatically deduce the argument type of a template by using class template argument deduction (CTAD). You can skip defining the templates arguments explicitly if the constructor is able to deduce all template parameters.

So you simply write

int main()
{
    std::vector v{2, 4, 6, 8};      // same as std::vector<int>
    std::list   l{1., 3., 5.};      // same as std::list<double>
    std::pair   p{false, "hello"};  // same as std::pair<bool, const char *>
    
    std::cout << typeid(v).name() << std::endl;
    std::cout << typeid(l).name() << std::endl;
    std::cout << typeid(p).name() << std::endl;
}

Under MSVC, it produces the following output

class std::vector<int,class std::allocator<int> >
class std::list<double,class std::allocator<double> >
struct std::pair<bool,char const * __ptr64>

Kindly refer CTAD for more details.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文