如何使用 Clang 的属性`preferred_name`?

问题描述 投票:0回答:1

Clang 有一个非标准属性

preferred_name
,例如使用在 libc++ 中将
std::basic_string<char>
拼写为
std::string
(这对用户更友好)。

我试图将它用于我自己的类型,但它似乎不起作用:https://gcc.godbolt.org/z/re4af1Pej

#include <iostream>
#include <string>

template <typename T>
void foo()
{
    std::cout << __PRETTY_FUNCTION__ << '\n';
}

template<typename T> struct my_basic_string;
using my_string = my_basic_string<char>;
template<typename T> struct __attribute__((__preferred_name__(my_string))) my_basic_string;

int main()
{
    foo<std::string>(); // std::string
    foo<my_string>(); // my_basic_string<char>   -- But why not `my_string`?!
}

请注意,这必须在 Clang 上使用

-stdlib=libc++
进行测试(libstdc++ 没有此注释,并打印
std::basic_string<char>
而不是
std::string
)。

我的语法有错误吗?我相信我正在做与 libc++ 相同的事情:[1][2]

c++ attributes clang
1个回答
0
投票

这似乎是一个 Clang 错误,我现在已在此处报告了该错误。

除非您在 TU 中的某处以特定方式使用目标类型,否则该属性不起作用。例如,在属性下方的某处添加

using X = my_basic_string<char>;
可以修复该问题(但
... = my_string;
不起作用)。定义此类并声明
my_string
(或
my_basic_string<char>
)类型的变量也可以解决此问题。

我创建了一个宏,可以自动应用此解决方法(并且还禁用不支持它的编译器上的属性):

在 gcc.godbolt.org 上运行

MY_CANONICAL_TYPEDEFS( (template <typename T> struct), my_basic_string,
    (my_string, my_basic_string<char>)
    (my_wstring, my_basic_string<wchar_t>)
)
#include <type_traits>

#if defined(_MSC_VER) && !defined(__clang__) && (!defined(_MSVC_TRADITIONAL) || _MSVC_TRADITIONAL == 1)
#error The standard-conformant MSVC preprocessor is required, enable it with `/Zc:preprocessor`.
#endif

#define MY_IDENTITY(...) __VA_ARGS__
#define MY_END(...) MY_END_(__VA_ARGS__)
#define MY_END_(...) __VA_ARGS__##_END

#define MY_CANONICAL_TYPEDEFS(type_, name_, aliases_) \
    MY_IDENTITY type_ name_; \
    MY_END(DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_USING_A aliases_) \
    DETAIL_MY_CANONICAL_TYPEDEFS(type_, name_, aliases_)

#define DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_USING_BODY(name_, target_) using name_ = target_;
#define DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_USING_A(...) DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_USING_BODY(__VA_ARGS__) DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_USING_B
#define DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_USING_B(...) DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_USING_BODY(__VA_ARGS__) DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_USING_A
#define DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_USING_A_END
#define DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_USING_B_END

#if defined(__has_attribute)
#if __has_attribute(__preferred_name__)
#define DETAIL_MY_CANONICAL_TYPEDEFS(type_, name_, aliases_) \
    MY_IDENTITY type_ \
        MY_END(DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_ATTR_A aliases_) \
        name_; \
    DETAIL_MY_CANONICAL_TYPEDEFS_CLANG_WORKAROUND(aliases_)

#define DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_ATTR_BODY(name_, target_) __attribute__((__preferred_name__(name_)))
#define DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_ATTR_A(...) DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_ATTR_BODY(__VA_ARGS__) DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_ATTR_B
#define DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_ATTR_B(...) DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_ATTR_BODY(__VA_ARGS__) DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_ATTR_A
#define DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_ATTR_A_END
#define DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_ATTR_B_END

#ifdef __clang__ // Workaround for bug: https://github.com/llvm/llvm-project/issues/106358

#define DETAIL_MY_CANONICAL_TYPEDEFS_CLANG_WORKAROUND(aliases_) \
    MY_END(DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_TOUCH_A aliases_)

#define DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_TOUCH_BODY(name_, target_) static_assert((void(std::type_identity<target_>{}), true));
#define DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_TOUCH_A(...) DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_TOUCH_BODY(__VA_ARGS__) DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_TOUCH_B
#define DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_TOUCH_B(...) DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_TOUCH_BODY(__VA_ARGS__) DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_TOUCH_A
#define DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_TOUCH_A_END
#define DETAIL_MY_CANONICAL_TYPEDEFS_LOOP_TOUCH_B_END

#else // no workaround needed
#define DETAIL_MY_CANONICAL_TYPEDEFS_CLANG_WORKAROUND(aliases_)
#endif

#else // this attribute is not supported
#define DETAIL_MY_CANONICAL_TYPEDEFS(type_, name_, aliases_)
#endif

#else // no __has_attribute
#define DETAIL_MY_CANONICAL_TYPEDEFS(type_, name_, aliases_)
#endif
© www.soinside.com 2019 - 2024. All rights reserved.