是否可以编写一个模板来改变行为,具体取决于是否在类上定义了某个成员函数?
这是我想写的一个简单例子:
template<class T>
std::string optionalToString(T* obj)
{
if (FUNCTION_EXISTS(T->toString))
return obj->toString();
else
return "toString not defined";
}
Run Code Online (Sandbox Code Playgroud)
所以,如果class T
已经toString()
确定的话,就使用它; 否则,它没有.我不知道怎么做的神奇部分是"FUNCTION_EXISTS"部分.
auto
在(可能)用C++ 17引入的模板参数中有哪些优点?
它只是auto
我想要实例化模板代码的自然扩展吗?
auto v1 = constant<5>; // v1 == 5, decltype(v1) is int
auto v2 = constant<true>; // v2 == true, decltype(v2) is bool
auto v3 = constant<'a'>; // v3 == 'a', decltype(v3) is char
Run Code Online (Sandbox Code Playgroud)
我还从这个语言功能中获得了什么?
是否有可能根据C++ 11中的C++ 11表达式是否为常量表达式(即constexpr
)生成编译时布尔值?关于SO的几个问题与此有关,但我在任何地方都没有看到直接答案.
我试图实现一个类似于std::is_constructible
异常的值模板,只有当类型在constexpr环境中可复制时才是真的(即它的复制构造函数是constexpr限定的).我到达了以下代码:
#include <type_traits>
struct Foo {
constexpr Foo() = default;
constexpr Foo(const Foo&) = default;
};
struct Bar {
constexpr Bar() = default;
Bar(const Bar&);
};
namespace detail {
template <int> using Sink = std::true_type;
template<typename T> constexpr auto constexpr_copiable(int) -> Sink<(T(T()),0)>;
template<typename T> constexpr auto constexpr_copiable(...) -> std::false_type;
}
template<typename T> struct is_constexpr_copiable : decltype(detail::constexpr_copiable<T>(0)){ };
static_assert( is_constexpr_copiable<Foo>::value, "");
static_assert(!is_constexpr_copiable<Bar>::value, "");
Run Code Online (Sandbox Code Playgroud)
现在我问自己这是否符合标准,因为编译器似乎不同意输出. https://godbolt.org/g/Aaqoah
编辑(c ++ 17功能):
在is_constexpr_constructible_from
使用c ++ 17的新的自动非类型模板类型实现稍微不同的时候,我再次发现编译器之间的区别,当在constexpr表达式中取消引用nullptr时SFINAE
.
#include <type_traits>
struct Foo …
Run Code Online (Sandbox Code Playgroud) 在C++ 11中,我使用constexpr函数作为模板参数的默认值 - 它看起来像这样:
template <int value>
struct bar
{
static constexpr int get()
{
return value;
}
};
template <typename A, int value = A::get()>
struct foo
{
};
int main()
{
typedef foo<bar<0>> type;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
G ++ 4.5和4.7编译它,但Clang ++ 3.1没有.来自clang的错误消息是:
clang_test.cpp:10:35: error: non-type template argument is not a constant expression
template <typename A, int value = A::get()>
^~~~~~~~
clang_test.cpp:17:19: note: while checking a default template argument used here
typedef foo<bar<3>> type;
~~~~~~~~~^~
clang_test.cpp:10:35: note: undefined function …
Run Code Online (Sandbox Code Playgroud) 我可以在编译时检测"函数参数" 1是否是编译时常量?
例如,一个函数print(int i)
可以"constant 5"
在被调用时打印,print(5)
但"non-constant 5"
如果被调用为print(i)
where,i
则是一些非常量变量.特别是,在"is constant"分支中,我应该能够将其i
视为constexpr,包括将其用于模板参数等.
宏技巧,模板元编程和SFINAE技巧都可以.理想情况下它是可移植的,但是编译器特定的解决方案总比没有好.
如果存在"错误否定"则可以 - 即,如果常量值有时被检测为非常数(例如,禁用某些优化时).
如果解决方案可以检测到常量值何时间接传递给函数(例如,当一个常量值传递给调用的中间函数print
并且随后内联将常量暴露给print
)时,可以获得奖励积分.最后一种行为显然取决于优化.
如果它自然延伸到多个参数,则可获得双倍奖励
如果一个人可以使用和不带constexpr
参数重载函数的版本,这可能是直截了当的,但你不能.
1我在这里引用"函数参数",因为解决方案并不严格要求在函数内(或在具有特殊参数的调用者/被调用者边界)检测此状态 - 它只需要像函数一样出现给调用者但是可以使用宏或其他技巧,如静态对象operator()
等.
这里的"非依赖"是指"非依赖于该特定函数模板的任何其他模板参数".
在回答这个问题时,我认为我找到了答案,但根据@Johannes(在我的回答评论中),我在这里误解了标准.采用以下简单示例:
#include <type_traits>
template<class T>
struct X{
template<class U = typename T::type>
static void foo(int){}
static void foo(...){}
};
int main(){
X<std::enable_if<false>>::foo(0);
}
Run Code Online (Sandbox Code Playgroud)
(现场版.)
以上编译有保证吗?GCC和Clang在这里不同意,可以在实时版本中看到它们之间的切换.有趣的是,GCC接受以下内容:
#include <type_traits>
template<class T>
struct X{
template<bool = T::f()>
static void foo(int){}
static void foo(...){}
};
struct Y{
static bool f(){ return true; }
};
int main(){
X<Y>::foo(0);
}
Run Code Online (Sandbox Code Playgroud)
(现场版.)
第二个片段只有foo(int)
在T
包含constexpr
静态函数时才会打印f
.再说一次,有趣的是,如果你完全f
从中删除Y
(或通过,int
相反),GCC会抱怨缺少一名成员,表明它不允许SFINAE - 这与之前的观察相矛盾.Clang采用所有变化并应用SFINAE,我想知道这是否是标准所保证的. …
这是用SFINAE检测constexpr的后续问题.
我想检测一个元组的元素(或任何可以使用的元素std::get
)是否为constexpr.所以我编写了以下助手,类似于Xeo给出的:
template<size_t> struct sfinae_true : std::true_type{};
template<size_t N, class T>
auto check(const T& arg) -> sfinae_true<(std::get<N>(arg),N)>;
template<size_t N, class>
std::false_type check(...);
Run Code Online (Sandbox Code Playgroud)
现在我的测试驱动代码:
int main()
{
constexpr std::tuple<size_t, size_t> arg(4,5);
typedef decltype(check<0,decltype(arg)>(arg)) is_cexpr;
std::cout << "is constexpr? " << is_cexpr::value << '\n';
}
Run Code Online (Sandbox Code Playgroud)
但是,这总是打印出来false
给我!要检查由于某种原因并不总是调用错误的重载,我注释掉了错误的重载并得到编译器错误:
注意:候选模板被忽略:替换失败[N = 0,T = const std :: tuple]:非类型模板参数不是常量表达式
自动检查(const T&arg) - > sfinae_true <(std :: get( ARG),0)>;
但是,我知道我可以调用std::get<N>(arg)
并获得constexpr值:
template<size_t N>
class A{};
int main()
{
constexpr std::tuple<size_t, size_t> …
Run Code Online (Sandbox Code Playgroud) 因此,我想做一些高级的类型级黑客技术,我真的希望能够编写一个概念,要求类型具有constexpr int
与其关联的值,稍后我可以在与整数std::array
模板参数。
可以写
template<typename T>
concept bool HasCount = requires {
typename T::count;
};
Run Code Online (Sandbox Code Playgroud)
但这不是我想要的;我想T::count
成为一个static constexpr int
。但是,代码(甚至不包括所需的constexpr
)
template<typename T>
concept bool HasCount = requires {
int T::count;
};
Run Code Online (Sandbox Code Playgroud)
在 GCC 7.3.0 上编译时不会出现“错误:预期的主表达式在 'int' 之前”。
另一个失败的尝试:可以这样写,这需要static int T::count()
:
template<typename T>
concept bool HasCount = requires {
{T::count()} -> int;
};
Run Code Online (Sandbox Code Playgroud)
但不是这个,这就是我想要的:
template<typename T>
concept bool HasCount = requires {
{T::count()} -> constexpr int;
{T::count() constexpr} -> int; // or …
Run Code Online (Sandbox Code Playgroud) 设置:
我有一个使用 SIMD 内在函数的函数,并希望在一些 constexpr 函数中使用它。
为此,我需要使其成为 constexpr。但是,SIMD 内在函数没有标记为 constexpr,编译器的常量评估器无法处理它们。
我尝试用执行相同操作的 C++ constexpr 实现替换 SIMD 内在函数。该函数在运行时变慢了 3.5 倍,但我能够在编译时使用它(是吗?)。
问题:
如何在常量表达式中使用此函数而不会在运行时减慢程序速度?
一些想法:
更务实的解决方案是:
无论如何,我愿意接受任何解决我问题的建议。
提示:
__builtin_constant_p
来检测函数参数是否都是常量表达式,在这种情况下,编译器希望至少尝试在编译时评估函数。失败的尝试:
我想检查一个函数是否可以在编译期间被评估。我发现了这个,但我不完全理解这个概念。我有几个疑问:
代码中下面这行的作用是什么?
template<int Value = Trait::f()>
每次当我需要检查该函数是否可以在编译时评估时,是否需要将其设为某个结构的成员函数?
PS
我复制链接中的代码,只是为了方便。
template<typename Trait>
struct test
{
template<int Value = Trait::f()>
static std::true_type do_call(int){ return std::true_type(); }
static std::false_type do_call(...){ return std::false_type(); }
static bool call(){ return do_call(0); }
};
struct trait
{
static int f(){ return 15; }
};
struct ctrait
{
static constexpr int f(){ return 20; }
};
int main()
{
std::cout << "regular: " << test<trait>::call() << std::endl;
std::cout << "constexpr: " << test<ctrait>::call() << std::endl;
}
Run Code Online (Sandbox Code Playgroud) c++ ×11
constexpr ×7
templates ×5
sfinae ×4
c++11 ×3
c++14 ×2
c++17 ×2
compile-time ×2
auto ×1
c++-concepts ×1
clang ×1
gcc ×1
intrinsics ×1
optimization ×1
simd ×1