随着C++ 14中的变量模板(以及Clang已经支持它们)和标准is_same_v类型特征的提议,我认为能够制作新的类型特征如下:
template<typename T>
constexpr bool is_const_and_volatile{std::is_const_v<T> && std::is_volatile_v<T>};
Run Code Online (Sandbox Code Playgroud)
唉,这会导致错误等同于以下SSCCE(这个包含下面提到的所有内容):
#include <type_traits>
template<typename T>
constexpr bool is_pointer{std::is_pointer<T>::value};
template<typename T>
constexpr bool foo{is_pointer<T>};
int main() {
//foo<int *>;
}
Run Code Online (Sandbox Code Playgroud)
在main评论中,Clang吐出以下内容:
警告:变量
is_pointer<type-parameter-0-0>具有内部链接但未定义
它看起来定义为我的(注意,更改T到int *在foo正常工作).在取消注释行main实例foo给出了这样的(再次,T以int *优良工程):
错误:constexpr变量
foo<int *>必须由常量表达式初始化
但是,foo使用以下旧语法替换会导致两个实例都正常工作:
constexpr bool foo{std::is_pointer<T>::value};
Run Code Online (Sandbox Code Playgroud)
关于变量模板有什么我想念的吗?有没有办法用它们构建新的变量模板,或者我是否被迫使用旧的语法来构建新的模板,并且在将它们用于其他代码时只享受语法糖?
在以下程序中,全局变量isCompleteType<Apple>由 clang 和 gcc 以不同的方式初始化(位于Godbolt.org 上):
template <class T>
constexpr bool IsCompleteTypeHelper (decltype (sizeof (T))) { return true; }
template <class T>
constexpr bool IsCompleteTypeHelper (...) { return false; }
template <class T>
bool isCompleteType = IsCompleteTypeHelper<T> (0);
class Apple;
int main ()
{
return isCompleteType<Apple>;
}
class Apple {};
Run Code Online (Sandbox Code Playgroud)
isCompleteType<Apple>为true.isCompleteType<Apple>为false.由于Apple可以生成变量的定义true是在的实例化之后isCompleteType,因此我得出结论,编译器在初始化变量时会执行以下操作。
c++ language-lawyer incomplete-type variable-templates c++14
C++14 添加了变量模板,它定义了相关变量组。在标准库中,变量模板用于访问每个类型特征的值成员:
template<class T>
inline constexpr bool is_arithmetic_v = is_arithmetic<T>::value;
Run Code Online (Sandbox Code Playgroud)
C++17 添加了内联变量以更好地支持仅头文件库,这些库可以包含在同一应用程序内的多个源文件中(不同的翻译单元中允许相同的内联变量定义)。但就变量模板而言,无论如何它们都可以在程序中具有多个定义。那么,如果变量模板已经免于 ODR,还有什么理由将它们声明为内联呢?
只要很多人都关注constexpr差异inline constexpr,这是另一个有趣的问题,我就想忽略constexpr这次讨论的目的。
template <typename T>
bool myVar = sizeof(T) > 1;
Run Code Online (Sandbox Code Playgroud)
它与以下内容有何不同:
template <typename T>
inline bool myVar = sizeof(T) > 1;
Run Code Online (Sandbox Code Playgroud) 这似乎是另一个"谁做得好"?问题,因为gcc 6.0.0和clang 3.7.0表现不同.
假设我们有一个变量模板,它采用const char *非模板参数,并且专用于给定的指针:
constexpr char INSTANCE_NAME[]{"FOO"};
struct Struct{ void function() const { std::cout << __PRETTY_FUNCTION__; } };
std::ostream &operator <<(std::ostream &o, const Struct &) { return o << INSTANCE_NAME; }
template <const char *> char Value[]{"UNKNOWN"};
// spezialization when the pointer is INSTANCE_NAME
template < > Struct Value<INSTANCE_NAME>{};
Run Code Online (Sandbox Code Playgroud)
请注意,模板变量具有不同的类型,具体取决于特化.十,我们有两个模板函数,每个函数都有一个const char *非模板参数,并将其转发给变量模板:
template <const char *NAME> void print()
{
std::cout << Value<NAME> << '\n';
}
template <const char *NAME> void …Run Code Online (Sandbox Code Playgroud) 我知道我可以部分专门化类模板,我知道我不能部分指定函数模板.
变量模板怎么样?我找不到关于它们是否可以部分专业化的文档.
c++ templates partial-specialization language-lawyer variable-templates
在查看C++ 14的元函数别名提议(TransformationTraits Redux,v2,N3655)时,我注意到,不仅类型转换类型(例如add_const),类型到值元函数(例如is_void)也是类型别名.(N3797中没有).
混淆类型对元函数的值是否有任何优势?我认为,可以在没有这些别名的情况下使用它们,例如enable_if_t<is_void<T>::value,T>或enable_if_t<is_void<T>{}(),T>存在转换操作时.(我猜is_void<T>::type::value是一样的is_void<T>::value)
如果类型值元函数需要是别名,不要将它们作为变量模板别名(我没有C++ 14编译器,也从不使用变量模板.所以语法可能是错误的)?例如别名is_void为
template <class T>
constexpr bool is_void_t = is_void<T>::value;
Run Code Online (Sandbox Code Playgroud)
代替
template <class T>
using is_void_t = typename is_void<T>::type;
Run Code Online (Sandbox Code Playgroud)
然后一个人可以在enable_if_t<is_void_t<T>,T>没有助推风格的情况下写作enable_if,并且构图表达将更容易(例如enable_if_t<(is_void_t<T> || is_integral_t<T>),T>
我想在头文件中转发声明变量模板,然后在单独的编译单元中进行实际实例化.
我被引导相信C++ 14变量模板的运行方式与静态类变量非常相似.不幸的是,这似乎并非如此,它阻止我向前声明我的变量模板.
template <typename T> struct Variable {
static int variable;
};
template <typename T>
extern int variable;
int main() {
(void) Variable<char>::variable;
// (void) variable<char>; // <-- line 10
}
template <> int Variable<char>::variable = 42;
template <> int variable<char> = 23;
Run Code Online (Sandbox Code Playgroud)
上面的代码示例在GCC下编译并按原样运行.但是,取消注释第10行会产生编译时错误:
specialization of 'variable<char>' after instantiation
template <> int variable<char> = 23;
^
Run Code Online (Sandbox Code Playgroud) 当我尝试为通用容器(例如std::list<...>,而不是特定容器,例如std::list<double>)专门化模板变量时,我收到链接错误gcc 5.3(但不是clang 3.5)
/tmp/ccvxFv3R.s: Assembler messages:
/tmp/ccvxFv3R.s:206: Error: symbol `_ZL9separator' is already defined
Run Code Online (Sandbox Code Playgroud)
http://coliru.stacked-crooked.com/a/38f68c782d385bac
#include<string>
#include<iostream>
#include<list>
#include<forward_list>
#include<vector>
template<typename T> std::string const separator = ", ";
template<typename... Ts> std::string const separator<std::list<Ts...> > = "<->";
template<typename... Ts> std::string const separator<std::forward_list<Ts...>> = "->";
int main(){
std::cout << separator<std::vector<double>> << '\n';
std::cout << separator<std::list<double>> << '\n';
std::cout << separator<std::forward_list<double>> << '\n';
}
Run Code Online (Sandbox Code Playgroud)
(这可以很好地编译clang 3.5并按预期工作。此外,可变参数模板不是导致问题的原因,我尝试使用非可变参数模板)。
如果这不是 中的错误gcc,您认为有解决方法吗?我尝试使用类专业化,但也不可能:
template<class T>
struct separator{ …Run Code Online (Sandbox Code Playgroud) 我有以下代码:
// Case #1
float f = 1.0f;
float f2 = sqrt(f * pi);
// Case #2
double d = 1.0;
double d2 = sqrt(d * pi);
Run Code Online (Sandbox Code Playgroud)
有什么办法来定义变量pi,以便operator*与sqrt将在操作floatS IN案例#1,但在操作double中的情况#2秒?
也许C++ 14变量模板可能有用吗?
如果我进行部分专业化,我会从 clang 和 g++ 得到不同的结果。
template < typename T>
class X
{
public:
T i;
X(T _i): i{_i}{}
operator T(){ return i; }
};
template < typename T2 >
class Y
{
public:
template <typename T>
static X<T> x_in_y;
};
template< typename T2>
template< typename T>
X<T> Y<T2>::x_in_y{200};
template<>
template<>
X<float> Y<int>::x_in_y<float>{100};
template<>
template<>
X<int> Y<int>::x_in_y<int>{101};
template< >
template< typename T >
X<T> Y<bool>::x_in_y{77};
int main()
{
std::cout << Y<int>::x_in_y<int> << std::endl;
std::cout << Y<int>::x_in_y<float> << std::endl;
std::cout << Y<float>::x_in_y<float> …Run Code Online (Sandbox Code Playgroud) c++ templates template-specialization variable-templates c++14
我有一堆这样的结构,其中成员数量不断增加,但成员命名却保持一致:
struct one { int a; };
struct two { int a; int b; };
struct three { int a; int b; int c; };
Run Code Online (Sandbox Code Playgroud)
我也有一个模板化函数,我希望接受以下这些结构的成员之一:
template <typename T, typename ... ARGS> // T will be one, two, or three
void func(ARGS... args); // This should take 1, 2, or 3, int arguments respectively
Run Code Online (Sandbox Code Playgroud)
我希望能够这样称呼:
two foo;
func<two>(splatter(foo));
Run Code Online (Sandbox Code Playgroud)
哪里splatter会以某种方式分裂,foo以便解决func<two>(foo.a, foo.b)。
显然,我可以只扩展此内联,而无需splatter,但是我调用的代码func本身很容易被模板化。我已经尝试过使用,initializer_list但是我不知道如何仅基于模板类型来构建一个。
不幸的是,我的编译器也不支持constexpr if对splat的调用func或构建initializer_list …
如何引入static_assert模板变量定义?
我的尝试是使用 lambda 函数:
#include <type_traits>
#include <utility>
#include <cstdlib>
namespace
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wglobal-constructors"
template< typename F >
F f = ([] () { static_assert(std::is_default_constructible< F >{}); }(), F{});
#pragma clang diagnostic pop
}
struct L
{
L() = default;
L(L const &) = delete;
L(L &&) = delete;
};
int
main()
{
static_cast< void >(f< L >);
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
但对于不可移动的对象,不可能以这种方式构造值对象。
使用逗号运算符我无法在 form 中执行值初始化F f = ([] () { …
C++ 14引入了变量模板(Variable templates).
template<class T>
constexpr T pi = T(3.1415926535897932385); // variable template
template<class T>
T circular_area(T r) // function template
{
return pi<T> * r * r; // pi<T> is a variable template instantiation
}
Run Code Online (Sandbox Code Playgroud)
在二进制内存占用和运行速度方面,使用它的开销是多少?